Yesterday xETHeREALx posted on reddit about replay attacks with a hard fork. Some of his/her concerns seem a bit overblown, but there are a few high quality attack vectors everyone should be talking about.
Cross Chain Replays
Put simply, if one fork has a valid transaction, the concern is that the transaction could be 'replayed' into the other fork, and havoc could ensue.
We can imagine a transaction from the 'main' fork coming to the 'old' fork, or the other way around.
Don't Forks Resolve?
In the typical case of a fork, they resolve quickly. When a hard fork triggers social concerns, then a minority group may end up running the fork for some time, or all time.
Essentially, the universe has forked, and some people choose to stay in the old universe. Could this happen in Ethereum? xETHeREALx noted some significant support for the 'old' chain online. If an exchange provides support for the 'old' chain, then there will be liquidity and some value to that fork's coins, and this might push additional support; perhaps people will trade their alt-universe coins for Bitcoin, and back to 'real' Ether, at the very least.
This is New
We are in somewhat uncharted territory here, as far as I know -- certainly no expressive-transaction-language blockchain has forked with support for both sides of the chain yet.
What could possibly go wrong? I'm looking forward to finding out. Here are a few angles of attack that seem worrisome to me.
The replay attack is simple -- take a valid transaction on one chain, and offer it on the other one. Since there's nothing to distinguish which chain a transaction has come from, in the reductive case, they will both do the same thing.
If an exchange has paid someone on one chain, then reissuing the withdrawal on another chain will result in the same spend. Similarly, any function call can be copied in this way.
We are ignoring transaction nonces right now; I'll get back to them later in the article.
"Soak the Exchange" Attack
If an exchange wants to participate in both chains, they have a real problem -- if user A deposits on "old" chain and then withdraws, they can take the withdrawal payment and offer it on the "new" chain, presumably doubling up their money (pending some exchange rate differences between the two Ethers). This is the core attack vector mentioned in the reddit article.
This isn't the only worrisome action; in particular since arbitrary function calls can be replayed, there are lots of possible funny things for participants in both chains.
Ethereum does not keep track of individual transaction outputs (txos) like Bitcoin, but it does have a mechanism for uniquely identifying a transaction : each transaction issued by an address has a 'nonce' -- a number that increments once per transaction.
If a transaction is issued with a nonce that is too low -- e.g. a different transaction has already been offered -- the transaction is ignored, it is considered invalid.
if a transaction is issued with a nonce that is too high -- e.g. we haven't seen some intermediate transactions yet, then it is held in the pool of transactions until it is in order.
What does this mean for a cross-chain withdrawal attack?
A Working Cross-Chain Attack With Nonces
So, to get this working, we need
- A participant on both chains
- A way to iterate the attack victims nonce
- Good timing
Note that we don't even need an exchange participating on the 'old' chain -- Only the attacker need use both chains. Let's imagine the following participants
- "Modern" Exchange only working on the main chain
- "Principled" Exchange only working on the old chain
- "Attacker" on both chains
Now, how do we proceed?
- Attacker withdraws from the "Modern" exchange to an address they control on the main chain.
- Attacker replays the withdrawal, and any withdrawals needed to get the nonce up to the correct number on the "Principled" chain.
- The attacker now has the same coins on both chains.
- Attacker sends coins to the "Principled" exchange, sells, and turns those into Bitcoin.
The universes have been merged, and the attacker has gotten extra value.
Note that the nonce management is tricky; if the attacker can't get up to the proper nonce, the transaction will be held in the pool. If the "Modern" exchange participates on the "Principled" chain, they can increase the nonces past the withdrawal.
Timing and Philosophy
Timing worries are not good worries in distributed systems, and this sort of complexity is not something that digital currency exchanges are used to worrying about right now, they treat a time delayed chain as essentially invariant, and go about their business. This could be a real worry, needless to say.
On the other hand, should they care what happens with their old alternate universe coins? Maybe not -- they are committed to the "Modern" chain, and anything that causes havoc in the "Principled" chain just builds the value of the "Modern" chain.
If these attacks become common, presumably the "Principled" coins will drop in value, and at some level the attack will take care of itself.
Even if not, though you should care about the "Principled" chain.
You Should Care About the "Principled" Chain: SPAM
There's a very cheap attack from Principled -> Modern that comes to mind; spam. The Principled chain will include a huge number of transactions. These can be put into the main chain, skipping any transaction that has a sequential nonce. Since Principled participants will generally not be participating in the Modern chain, these txs will sit in the tx pool, clogging things up.
This is an incredibly simple and cheap attack; other network participants are going to be creating the valid transactions for the attacker.
Mitigation 1: Stop Accepting Future-Nonce Txs
First things first, geth should stop taking out of order txs; this responsibility should be the client's. The equivalent has been true in Bitcoin for a long time, and it seems like a bit of sensible infrastructure management that will only help.
Mitigation 2: Nonce management or Cold Storage
If exchanges want the ability to someday reclaim their coins in the "Principled" chain, it makes sense for them to massively increase their nonce, by at least a year of usage, accomplished probably by spending or calling something cheap. This will cost gas, but leave options open for the future.
Alternately, the exchanges could create a "Principled" cold storage address and send everything there, rendering withdrawal replays ineffective.
This seems like a very good idea if there is any chance the minority fork will be used.
Lots To Learn
I'd bet 10 Eth there are some much more interesting cross-chain replays with function calls, things that are going to be very, very interesting and weird.
I'd urge the Ethereum community as a whole to drop the losing fork, especially exchanges or other groups that could give financial incentive to keep up with the losing chain.
As always, I'm available for audits and security consultation relating to blockchains and smart contracts: [email protected].