Bruteforcing Bitcoin Seed Phrases

Checking Bitcoin Seed Phrases for transactions and balances

I was recently in a situation where I had 10 words from a 12 word Bitcoin seed phrase, I also knew the order of the words. A mnemonic seed sentence ("mnemonic seed", "mnemonic code", "seed phrase") represents a large randomly-generated number as a sequence of words, which makes it easier for humans to store. Your Bitcoin private key, which is used to sign transactions and therefore control your unspent transaction outputs (utxo) is essentialy just a large random number, and using a seed phrase is a more simple way of backing up or remembering your private key. If you lose your key you lose your Bitcoin.

Private keys can be derived from the BIP39 Wordlist, and trying to brute force a valid key is impossible, this is what in part makes Bitcoin so secure. However, since I already had 10 of the possible 12 words and knew the order, I thought it was very much worth a punt. Manually importing each possible seed phrase into a software wallet like Blockstream Green is a non starter so I needed some way of scripting this. The goal being - take a list of potential seed phrases, generate the private key, then check a public block explorer like Blockstream (or preferably a private node) for any corresponding transactions and utxos. Existing tools on GitHub that purport to achieve this are severely lacking, hence I created Bitcoin seed phrase tester.

Key Paths and Addresses

When you receive Bitcoin on the blockchain, the transaction will be sent to a destination address under your control, this address is derived from your private key and resulting public key. In order to improve privacy by not reusing addresses wallets will use extended or child keys which follow a set derivation path. This allows many keys to be created from one private key / seed phrase and therefore many addresses on which bitcoin can be received. This also allows keys to be organised and more easily managed, for example in different "accounts" for better coin control and management of funds. Most wallets use common derivation paths which correspond to the type of address being used but there is still quite a bit of variation. This means its not as simple as taking the seed phrase, generating the private key, obtaining a Bitcoin address and checking that address for transactions and utxos. There are many potential addresses that could have been generated from that original seed phrase that need to be checked. Typically wallets will use key path "m/84'/0'/0'/0/0" first then "m/84'/0'/0'/0/1" and so on for native segwit example, but this is not always the case. Also the wallet user may have generated a number of addresses before using one further down the list. So if you were to only check the first address (as a number of scripts on Github do) you may not see any transactions.

The solution?

My rudimentary solution is https://gitlab.com/shaunwebber/bitcoin-seed-phrase-tester. This python script will ask for each word of the seed phrase that you know, any words you do not know can be left blank. The script will work out all possible valid seed phrase permutations by filling in the blanks and will then query the most common native (bc1addresses) and legacy (3addresses) segwit addresses in an online block explorer to see if there have been any transactions sent to those addresses and if they happen to have any utxos.

Example output

below is an example of the output when checking a easily guessable seed phrase consisting of the word all 12 times.

---
address: bc1qannfxke2tfd4l7vhepehpvt05y83v3qsf6nfkk
transactions: 12
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q43y46a6mtajyj5q5xprx5dh20qghnyr54vnwtg
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: 3L6TyTisPBmrDAj6RoKmDzNnj4eQi54gD2
transactions: 6
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: 3BS7JLzQi7cW1V5w3iS4iwMZmZzhjJGsd3
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q7e6qu5smalrpgqrx9k2gnf0hgjyref5p36ru2m
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: 3GMMgFUQiYTYQhuHQuZfQoXPvW3GPqfGmD
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q5f2lvs7t29wv8nwssse6a4f6099sc3nagchqyc
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: 3BKbtvJtLSjnSoGUYTeQ17tMKTuyqbUV7P
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q6hr68ewf72l6r7cj6ut286x0xkwg5706jq450u
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: 3Dyf1D6pVR6ZAQYN1th6ehgS1uqgGk1TGh
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q7zql632newlfv9rt269jyxdn30370rh4kp23pd
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1qfcjv620stvtzjeelg26ncgww8ks49zy8lracjz
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1quqgq44wq0zjh6d920zs42nsy4n4ev5vt8nxke4
transactions: 4
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1qunyzxr3gfcg7ggxp5vpxwm3q7t3xc52rcaupu4
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q2glg28yag4rdgrd0hj5ntdvva8cgrjdsku5prc
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q9z4cdmrgtfjsp34dmtvha98shje83jjn2t27z5
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1qgsjef02jrcjl6fha0d6jytmafcd0d95gh80n3y
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all
---
address: bc1q65f3kvtl54uqj2um9wv2cmf3hkefskzt29dd2z
transactions: 2
balance: 0 sats
mnemonic: all all all all all all all all all all all all

Using your own node

The script currently queries online block explorer APIs (blockstream.info and blockchain.info) this means that due to sending many HTTP requests and API rate limits this is very slow. A much faster solution would be to use your own local copy of the Bitcoin blockchain (aka a node like Bitcoin Knots ) to query transaction and balance information. There is a tool btcrecover that appears to do this, I am yet to set it up but will likely also write about this in the future.