Transactions in blockchain are like sound traveling through air. We communicate with others through transactions; we announce what we’re doing and to whom we’re sending the message to. We pay a fee for every transaction we submit, which enables it to be propagated to others.
But what if we could construct a transaction where we wouldn’t need to pay the fee? Moreover, what if we created a transaction that would be able to steal fees for the current block? Whitehat zb3 found a method to do exactly that in the Ethermint client for Cronos Blockchain and reported it before any malicious parties were able to exploit it, leading to a positive outcome for all.
By submitting a cosmos-signed MsgEthereumTx (with a valid Ethereum signature) without ExtensionOptionsEthereumTx and a high GasLimit, the attacker receives a “gas refund” even though the gas charge was not taken in the first place.
zb3 submitted the bug to Immunefi on December 12th. It was reported as a high severity report due to being classified as a “theft of yield” — user rewards were affected but funds not drained. zb3 received a bounty of $40K for this find from the Cronos team, followed by a swift bug fix from the team.
We will explain how the vulnerability was possible, but first, we will explain Cronos, Ethermint, and transactions in general.
As we can read from Cronos’ Medium:
“Built on the Cosmos SDK while being Ethereum Virtual Machine (EVM) compatible, Cronos is uniquely positioned to connect the EVM chains and Cosmos ecosystem to enable seamless crypto assets and dApps interoperability in the multichain world.”
Ethermint is the underlying technology that Cronos is built on. Ethermint is a high-throughput, scalable Proof-of-Stake (PoS) blockchain entirely compatible with Ethereum. The Cosmos SDK, which operates on top of the Tendermint Core consensus engine, was used to create it.
Ethermint is unique because it enables the use of vanilla Ethereum as a Cosmos application-specific blockchain. It gives developers access to all of Ethereum’s desirable features while also using Tendermint’s PoS implementation.
Since Ethermint is compatible with both EVM-based chains and Cosmos-specific blockchains, this also means the transactions can be bridged and propagated between the two chains. The client needs to parse and handle transactions routed for both the EVM and for the Cosmos hub.
According to the Ethermint documentation:
“We attempt to achieve this (note by author: transaction routing) by mimicking Geth’s Transaction structure and treat it as a unique Cosmos SDK message type. An Ethereum transaction is a single SDK.Msg contained in an auth.StdTx. All relevant Ethereum transaction information is contained in this message. This includes the signature, gas, payload, etc.”
That’s a lot of information, so we’ll break it down into pieces. First, we need to answer the following basic question: what is a blockchain transaction?
Transactions are one of Ethereum’s key functionalities, as they are the only thing that can modify or update the state of the blockchain. They are signed messages sent by the Ethereum network to every node via the “flood routing” protocol, i.e., gossip, and originated from an externally owned account (EOA).
Only transactions can cause a state change or a contract to execute in the EVM. Every contact a user will have with the blockchain will begin with a transaction.
The transaction structure looks as follows:Nonce: an originating EOA-issued sequence number used to prevent message replay.Gas price: how much Ether (in Wei) the originator is prepared to pay for each unit of gas.Gas limit: the quantity of gas the originator is prepared to purchase for this transaction.Recipient: the Ethereum address of the final destination. It may be another EOA or contract address.Value: the amount of Ether to transmit to the destination (in Wei).Data: variable-length binary data payload.v,r,s: the three components of the original EOA’s ECDSA digital signature.
Please check out our Introduction to Signatures if you want to learn more about the ECDSA.
How does Ethermint’s chain perform state transitions? By using MsgEthereumTx. This message provides the relevant transaction data elements and wraps an Ethereum transaction as an SDK message.
We won’t go into SDK.Msg and auth.StdTx because they have nothing to do with the issue. If you want to know what they do, consult the official Ethermint official docs.
When transactions are consumed in Ethermint, they pass via a sequence of handlers. The AnteHandler is one of these handlers, and it’s in charge of conducting preliminary message execution business logic such as fee payment, signature verification, and so on. It only applies to transactions conducted through the Cosmos SDK. Because the EVM handles the same business logic, Ethereum routed transactions will be unaffected.
Armed with this knowledge, an attacker may construct a transaction that will lead to the vulnerability outlined earlier by taking advantage of how the transactions are processed.
Ethermint offers standard JSON-RPC endpoints to utilize whenever we wish to send an Ethereum transaction. The MsgEthereumTx message is then wrapped around the transactions, with EthereumTx extension options added to execute the transaction differently than typical Cosmos SDK transactions. Every transaction has an anteHandler run for them, and if ExtensionOptionsEthereumTx is detected, a collection of AnteHandlers is picked to be performed for those transactions.
This eliminates the need for a cosmos signature, while also ensuring that the gas limit indicated in the Ethereum message is subtracted first, as it would on Ethereum.
However, there is no check to see if a MsgEthereumTx is truly included within a transaction with the ExtensionOptionsEthereumTx option; thus it’s possible to sign a standard cosmos transaction with MsgEthereumTx and execute the standard set of antehandlers by omitting this option. As a result, we may skip a few antehandlers that are supposed to run before MsgEthereumTx is handled.
One of the handlers that are called is EthGasConsumeDecorator(evmKeeper). Its primary purpose is to ensure that the Ethereum tx message has sufficient funds to cover intrinsic gas and that the sender has the funds to cover the gas cost. The quantity of gas consumed by a transaction before it is completed is referred to as intrinsic gas. This is different from the cosmos fee because it’s meant to be refunded.
But since gas costs are not deducted, it’s possible to specify an arbitrary gas limit and then get “refunded” gas that wasn’t deducted in the first place, as the EthGasConsumeDecorator handler didn’t run.
This means that before the malicious transaction is being executed, the transaction fees in the current block might be seized and the attack could be repeated for every block.
What Cronos did to fix the issue is they are now checking if the MsgEthereumTx is contained inside the transaction. This fix has been applied to the current Cronos mainnet beta in the binary upgrade of `v0.6.5` (see https://github.com/crypto-org-chain/cronos/security/advisories/GHSA-f854-hpxv-cw9r)
We would like to thank zb3 for doing an amazing job and coming up with this really interesting finding. Props also to the Cronos team who quickly responded to the report and rewarded the whitehat with $40K for the find.
This issue was reported responsibly and securely via the Immunefi platform, leading to a happy outcome for everyone, especially the users.
If you’re a Web2 or Web3 developer who is finally thinking about a bug-hunting career in Web3, we got you. Check out our ultimate blockchain hacking guide, and start taking home some of the cash rewards that are available on Immunefi — the leading bug bounty platform for Web3.