If you’ve been following the developing story in the Ethereum community over the last week, you know that there is an actor who is stealing funds from wallets by guessing seed phrases.
If you’re in cyber security or cryptocurrency, this is a pretty big deal. One of the promises of cryptocurrency is that your wallet information is public, but only you hold the private key. Thus, only you can move the funds.
However, as anyone who knows about asymmetric cryptography will tell you, that’s only partially true. A better statement is, provided your private key is unique enough, there is little probability that anyone else can move your funds other than you. But that little probability is a whole lot larger when you generate a private key from a seed phrase like “Password123”.
There is a commonly known attack in cyber security called “credential stuffing”, where an attacker guesses that a user will likely use the same credentials across many different websites.
I decided to test this theory in Ethereum.
Because the wallet balances are public information, it turns out it is fairly simple to credential stuff wallets. It took me about 3 days to build, test, and run at scale, enough to find my first vulnerable wallet.
Finding a source for seed phrases
While I won’t disclose the exact source of my seed phrases I used for credential stuffing, I’ll leave it up to the reader to find their favorite source of leaked user credentials online. At the last check, there are about 100 data breaches daily that are publicly disclosed online, as well as about 550,000,000 passwords that have been breached. For proof of this number, and to see if your own password is vulnerable, check out HaveIBeenPwned.
For my test, I used a subset of about 4,000,000 passwords from a 420,000,000 password dataset.
Checking a million wallets overnight
The next challenge I had was creating and checking millions of wallets quickly — and cheaply.
My first attempt was a single-threaded NodeJS app to check wallet balances. While this did work, it proved to take about 1 second round trip to read a seed phrase from a file, check the balance, and record the outcome.
This was just too slow. Enter AWS to the rescue.
Using a producer / consumer model, I created a Lambda script to take a seed phrase, create a private key from it, and then check the balance of the wallet. It then output to CloudWatch Logs the result of the balance query.
For the producer, I multi-threaded a NodeJS application from the command line of my local machine, reading local files of passwords and batch sending SQS messages. This allowed me to upload a number of potential seed phrases each second, vastly increasing my processing speed.
For about $50, I checked 4,000,000 wallets within a day. This was all without hitting more than 100 concurrent Lambda invocations. In other words, this was very cheap and could be done via the Free Tier of an AWS account if I had throttled invocations a bit.
Finding my first vulnerable wallet
It was about 6 hours into my run that I found my first wallet with a balance, proving that credential stuffing does theoretically work with cryptocurrencies. While the wallet balance was not on the same scale as the unknown Ethereum wallet bandit, the mere existence of a balance shows that this attack vector had not yet been tried.
I then continued to find vulnerable wallets at a rate of 1 wallet per million guesses. This proves that the total dataset of known breached passwords may yield a few hundred wallets with balances…on Ethereum alone.
The existence of a wallet with a balance means that neither the Ethereum bandit nor any state-level actor is currently scanning cryptocurrency chains using known breached credentials to steal funds.
Extrapolating the size of the problem
While it seems that the Ethereum bandit is moving small amounts of funds over thousands of transactions using a more complex — and statistically larger — set of private keys, one could guess that there are around a few hundred or so wallets that contain balances as a result of credential reuse.
Ethereum is no longer a chain only for techies. Many of the wallets now are generated using seed phrases, which would likely not occur in a breached password dataset.
However, if one were to look at more technical chains, where users generate their wallets from command lines, or an older chain, like Bitcoin, then I would theorize that more wallets are vulnerable.
When I think back to the history of the first cryptocurrency wallets, I know that brain wallets were popular cold storage mechanisms. Many of these wallets relied on human entropy for the initial seed phrase that generated the private key. It is likely that many of these wallets could be vulnerable to credential stuffing.
Weaponizing breached credentials
From my initial research, it is not difficult to combine some simple scripts and distributed processing power into a database of vulnerable wallets. On Ethereum, it is possible to further spin up your own Ethereum node and watch these addresses for incoming funds, much like the Ethereum bandit is likely doing. This would allow you to compute and enter a signed transaction to clean out an address at the next block mined.
At a large enough scale, a dedicated attacker could monitor 550,000,000 wallets or more across multiple cryptocurrencies, quickly “owning” billions of wallets based on breached credentials.
I would hypothesize that a DynamoDB or similar key-value store database could easily be used to store a pre-computed list of vulnerable wallets that are then checked based on incoming blocks of data in a modified distributed node. The total cost of such a system would likely be less than a thousand dollars, putting this attack within reach of a dedicated single actor.
The importance of not re-using passwords
As the mere existence of credential reuse in the Ethereum blockchain shows, never re-use a password between systems online. At least a few people have done so, and were technical enough to generate their own wallet from a re-used credential. Once these credentials are breached, all your cryptocurrency is essentially owned publicly by anyone who wants to generate your private key themselves.