Hello all, I'm (among other things) a graduate student getting a master's degree in cybersecurity. This last quarter for one of my classes, I was tasked to examine and recreate an exploit. For the actual exploit I was examining the "anyone can spend" segwit addresses on the BCH chain, and in my research I found a $600k theft that seems to have gone completely unnoticed.
You all might recall this $600k theft of segwit addresses, but it happened again in mid-February 2018 and there has been zero news about it.
BCH block 517171 contains solely segwit-stealing transactions. If you look at any given transaction, the inputs are all segwit program hashes spending a P2SH segwit output. I only caught it by accident, as I was originally going to talk about the publicized November attack.
The interesting thing I discovered about this was that it's harder to have stolen that segwit money than most people think. Both Unlimited and ABC nodes do not relay segwit-spending transactions, and Bitcoin ABC hard-coded in fRequireStandard, so you couldn't even force-relay them with a conf option. On top of that, miners keep their node IPs private for obvious avoiding-ddos-and-sybil-attack reasons, which means it's impossible to directly send transactions to miners. This means that the only way to actually execute this attack was to setup one's own mining pool running on a custom-modified client to allow non-standard transactions. Then you'd have to get enough hash power to mine a block yourself. I estimated the cost of renting enough hash power to do this at the time as around $30k-$60k to have a greater than 90% chance of mining a block within a 3 month window.
In order to simulate the attack, I spun up BTC, LTC, and BCH nodes in Docker, and wrote a Python script. The Python script started at segwit activation on BTC and LTC and it scanned every transaction in every block looking for P2SH segwit inputs as well as native segwit outputs, since these are the necessary hash pre-images to spend P2SH segwit money on the BCH chain. The script then also scanned the BCH chain for any native segwit outputs, as well as recording all P2SH outputs. (This was all saved in a MySQL database.) Then, at any point in time, I could simply query for BCH unspent native segwit outputs as well as P2SH outputs for which I had a known segwit hash pre-image. (If this was an attack I was doing real-time, I would probably also have a large mempool on each node and monitor unconfirmed tx's for useful info as well, but since this was after the fact, I just queried blocks sequentially.)
For the mining node that runs the pool, it would need to be firewalled behind (i.e. only connected to) an unmodified node in blocks-only mode, so that the segwit hash pre-images aren't transmitted out to the network, and so that no other unconfirmed transactions are transmitted in to the mining node. (The mining node should only be filling its block with segwit tx's in order to maximize the gain from the attack.)
Then a script should run continuously to grab segwit utxos from the MySQL database and construct high-fee transactions to send directly to the mining node. Unlike the November attack, each input should be spent in its own individual transaction, so that in the event it is individually spent, I don't negate a tx with other inputs. The overhead on having different transactions for each input is only about 8 extra bytes (the tx version and the locktime), so I think this is a good trade-off.
Then, the attacker simply rents hashing power and points it at his secret pool.
By the time February rolled around and the attack happened, my MySQL database had about 40 million BCH P2SH outputs and each query took about 3 minutes to execute. This of course would have been fine in the 10-minute block world of Bitcoin and BCH, but it means that I stopped my Python script after that time, so I don't know about any possible other attacks that happened before the clean stack rule was hard-forked into BCH.
It was pretty interesting to work through how this attack must have happened, and it was significantly harder to execute than I thought it would be given that all the money was "anyone can spend".
However, the most interesting thing about all this is that nobody has noticed. There is literally no news or mention of block 517171 or any of the transactions in it. My theory is that it is money that nobody misses -- i.e. misprogrammed custom wallet software for BTC nodes accidentally also sent out BCH transactions to the same address, given that BTC and BCH shared the same history until August 2017. And whatever person or entity is running those nodes is only thinking about BTC money and is completely oblivious to its misprogrammed problem of shipping BCH to segwit P2SH addresses.
Obviously, that's just a theory, but I think it's pretty reasonable. Given the intense community divide, I think it's very possible that a number of BTC users simply ignored money on the BCH chain, even though it's "free money" for them, simply out of ideological hatred.
Whatever the case, nobody has posted anywhere complaining of money stolen in that block. It seems to have gone completely unnoticed. (Which is why I'm posting this.) It was an interesting case study and I'd be curious to hear if anybody has any addition information or thoughts about it. I believe this was a different person than the November theft, because the way it was done was different -- the November theft had all the money in one transaction, but this February theft was done with separate individual transactions. Additionally worth noting is that the address which received the bulk of the money is still active, which means they're still out there.
Anyway, I thought this was interesting and worth posting.
No comments:
Post a Comment