Bruteforcing my own Bitwarden vault
Lately I lost the masterkey to my Bitwarden vault. As Bitwarden does not provide a way out of that rabbit hole, losing my masterkey would mean losing all of my data within the vault. Something around 300 entries.
Luckily I had access to the vault on one of my computers as the vault has not been locked there and on my mobile which is using Face ID to unlock my vault. But without my masterkey I was unable to export the entries, so my only choices had been
- lose everything
- transcribe all entries manually
- patch bitwarden Firefox extension so I could bypass the masterkey in order to export the vault
It goes without saying that option #1 is totally unacceptable. Option #2 was nice to have as a backup plan and option #3 was nice to know and something probably worthwhile to follow through someday.
But, as the title suggests, there is an other option: bruteforcing. My masterkey actually is a passphrase comprised of a number of words. I was pretty sure about which words most likely have been lost. I also had a list of candidates. Basically I assumed that I have no more than to two words which could have been wrong. So I searched my system for the wordlist used by bitwarden to generate passphrases and started to assemble a wordlist with likely candidates for bruteforcing. My final wordlist has 187735 candidates. I was also able to extract my keyHash from data.json and with a little help of a friend I also found how Bitwarden was generating the keyHash saved on disk which basically is
pepper = pbkdf2(sha256, pass = masterkey, salt = email, rounds = 100000)
keyHash = pbkdf2(sha256, pass = pepper, salt = masterkey, rounds = 1)
googling for a bitwarden specific bruteforcer was unsuccessful so the plan grew on me to write my own. As I still had access to the vault I was under no pressure at least not on the time front. Some hours later bw_brute.py has been conjured and tests with a list of one thousand entries finished in 9s on my 8 core, 16 threads Ryzen CPU which left me with some hope.
In the meantime remembrance kicked in and I was able to successfully remember my masterkey. This greatly helped in finalising the tool, eliminating some stupid bugs and working on the multiprocess part of the script (the above benchmark was done with the final version). So I ran the tool and lo and behold, nothing was found! After giving it some thought I found one fatal assumption in my approach: the words used for constructing my own wordlist. The vault itself is older than bitwarden itself and I migrated from another password manager to Bitwarden. I also – bad I know – recycled my old passphrase and obviously the wordlist used by the old password manager was different than what Bitwarden was using. As I was still curious about the performance of bw_brute.py I put the correct masterkey at roughly the position it would have been. 7 minutes and 16 seconds or 51789 attempts later I was able to “recover” my lost passphrase :-)
Having my data back I can now safely say that this was a frightening but also a funny experience and I am happy that I both remembered the correct masterkey and to successfully bruteforce myself!
--EOF