Sitemap

Recovering a lost seed phrase from sollet.io (Windows 10)

6 min readSep 24, 2021

Note: This requires you to know the password, if set, when you created your sollet.io wallet.

TLDR:

  1. Check if the word encrypted is in your Google Chrome Local Storage directory.
  2. If so, grep to find the json object (shown above). If not, attempt to recover older image of Local Storage .
  3. Clone my repository and edit the placeholder values to be your own.
  4. Run the code locally and view developer console to see your seed phrase.

Sollet.io provides you with a unique 24-word seed phrase when first creating a wallet. Unfortunately, sometimes seed phrases are lost due to unforeseen circumstances. When creating a wallet make sure you write down your seed phrase somewhere safe to avoid this problem. For those who forgot, in this guide I will outline a method of extracting your seed phrase from your Google Chrome Cache and decrypting it.

Extracting Vault Data (Windows 10)

The first action I took was to recover the oldest image possible of my hard drive, but specifically my Google Chrome folder. Ideally, the image will be from a time when you still had access to your sollet.io. If not, it is still possible that the seed phrase is stored in the cache.

I discovered that sollet can lose the pointer to where the vault is stored in memory, but not delete it. In this case you can find the phrase in one of the .ldb files inside Chrome's Local Storage directory.

Recovering a Windows 10 Image

For this step, I used ShadowExplorer. It allowed me to access the Shadow Copies created by the Windows Volume Shadow Copy Service. Shadow copies are snapshots that windows took of your system. Navigate to the Google Chrome folder and restore the oldest image of its Local Storage directory. It can be found at:

/c/Users/<user>/AppData/Local/Google/Chrome/User Data/Default/Local Storage

Here is a screenshot of me doing so.

ShadowExplorer

Once found, right click to export it somewhere you can easily access. You will need these files for the next steps.

The Local Storage directory contains the files in which you can find your sollet.io vault. This vault contains the information needed to retrieve your seed phrase.

Finding your sollet.io vault

For this section I will be using a Linux emulator to run commands. For simplicity I used GitBash, but using WSL 2 or PowerShell would work as well.

The json object containing the encrypted key looks like this.

{"encrypted":"2N423zNwqVqrtScqrsEKxXh472SVGg5Motz1jGzaLVcB9o9GvyC5hTC6b3rLAetxGQjSd7XBw7EC23dBgZjAkbktEY9o4P3rTqysU4gPnpWzMtuoJ6xJXkfxeeinJzqvV2j3gqpykV7kCnGrTmcWvzJbLzHK1gFKZ6vqrjV6pZp25Dn1KKyfVMcDW3ZYDKPKExp5VAzvuGph1X3DncaWPcaMVVDQyhoqGg4tZSCVxb6s2FvACVMKWhQb64iWAWaEWBLduZmxeN68jm6KfXRe9rFR9duev1ejCUwZARmCNPYzmt6wb1juS6VWiDYhJbSdCBYBfRDDMJuCSQx4nwH8S6RarZM1hv2g7xuMySFa2MBfaf94bdyrDmUSADzsenKves2MuBNpbK5nDDxEcEQ37ycRLrC9E2te7TgfLCS9EBvGxorS2KPRdYqWVJ44Eu59R643WAX6H4LGUL3K49okDPSZkvDesA2jZrZ","nonce":"7S6GafTc7UQGhwTM7FcpcCVEUBAUtzG6g","kdf":"pbkdf2","salt":"NcPCRE9UUzq5mvibicRN5L","iterations":100000,"digest":"sha256"}

The most important field is the “encrypted” field. It represents your seed phrase but encrypted using the password you set when creating your sollet.io, the salt, and nonce. Once found, you should copy the json somewhere you can access easily, you will need it later.

At this point I navigated to the restored Google folder, and then navigated to:

Google/Chrome/User Data/Default/Local Storage

Next I ran this command:

$ grep -r {\"encrypted\" leveldb/Binary file leveldb/109465.ldb matches

From the command you can see which file contains the match, in this case 109465.ldb .

From here I edited the file using the text editor vim(notepad works as well).

$ vim leveldb/109465.ldb

At this point I knew the encrypted value was in the 109465.ldb file, so I searched for “encrypted” using vim’s search functionality(/ ). You can search for any of the field names if you find other unrelated “encrypted” matches. Then I copied the json object to a text file for use later.

Now with this json object we can move onto to the last step, which is cloning the sollet.io repository (or my fork) and modifying their encryption function to print the seed phrase.

Cloning sollet.io’s repository

Note: All code modifications can be found at my github.

For this step you will need to clone the sollet.io repository and run their code locally on your machine. For my IDE I used VSCode, so the screenshots will represent that. First, I cloned their repository by running this command:

git clone https://github.com/project-serum/spl-token-wallet.git//To clone my repository (you will still have to replace my //placeholder values with your own from the json you found).git clone https://github.com/sifneR/spl-token-wallet.git

Once cloned, you want to access the file wallet-seed.js by navigating to spl-token-wallet/src/utils/ and opening the file. Once in the file, navigate to the method loadMnemonicAndSeed . You should be here:

Press enter or click to view image in full size
VSCode at wallet-seed.js

This code is loading a key from the json object’s salt, iterations, and digest values, plus the password you set when creating your wallet. From there it can generate the “plaintext” using that said key and the encrypted values from the json. This is the value we have been looking for.

To generate the key I needed to comment out the existing code, since it pulls from the Cache. Then replicate what it was doing using the values we got from the .ldb file. First, I decoded the values using bs58.decode , then generated the key. This is how you do that.

const encrypted = bs58.decode("2N423zNwqVqrtScqrsEKxXh472SVGg5Motz1jGzaLVcB9o9GvyC5hTC6b3rLAetxGQjSd7XBw7EC23dBgZjAkbktEY9o4P3rTqysU4gPnpWzMtuoJ6xJXkfxeeinJzqvV2j3gqpykV7kCnGrTmcWvzJbLzHK1gFKZ6vqrjV6pZp25Dn1KKyfVMcDW3ZYDKPKExp5VAzvuGph1X3DncaWPcaMVVDQyhoqGg4tZSCVxb6s2FvACVMKWhQb64iWAWaEWBLduZmxeN68jm6KfXRe9rFR9duev1ejCUwZARmCNPYidh6wb1juS6VWiDYhJbSdCBYBfRDDMJuCSQx4nwH8S6RarZM1hv2g7xuMySFa2MBfaf94bdyrDmUSADzsenKves2MuBNpbK5nDDxEcEQ37ycRLrC9E2te7TgfLCS9EBvGxorS2KPRdYqWVJ44Eu59R643WAX6H4LGUL3K49okDPSZkvDesA2jZrZ")const salt =  bs58.decode("NcPCRE9UUzq5mvibicRN5L")const nonce = bs58.decode("7S6GafTc7UQGhwQL7FcpcCVEUBAUtzG6g")const iterations = 100000const key = await deriveEncryptionKey("test-password", salt, iterations, "sha256")

So, the function should now look like this, where "test-password" is your actual password from the original wallet generation.

Note: Do not forget to console.log(decodedPlaintext) so the decoded plaintext can be seen from the console.

// Taken from my github
export async function loadMnemonicAndSeed(password, stayLoggedIn) { // const {
// encrypted: encodedEncrypted,
// nonce: encodedNonce,
// salt: encodedSalt,
// iterations,
// digest,
// } = JSON.parse(localStorage.getItem('locked'));
// const encrypted = bs58.decode(encodedEncrypted);
// const nonce = bs58.decode(encodedNonce);
// const salt = bs58.decode(encodedSalt);
// Generate Seed Phrase using json object
const encrypted = bs58.decode("2N423zNwqVqrtScqrsEKxXh123SVGg5Motz1jGzaLVcB9o9GvyC5hTC6b3rLZetxGQjSd7XBw7EC23dBgZjAkbktEY9o4P3rTqysU4gPnpWzMtuoJ6xJXkfxeeinJzqvV2j3gqpykV7kCnGrTmcWvzJbLzHK1gFKZ6vqrjV6pZp25Dn1KKyfVMcDW3ZYDKPKExp9EMqyuGph1X3DncaWPcaMVVDQyhoqGg4tZSCVxb6s2FvACVMKWhQb64iWAWaEWBLduZmxeN68jm6KfXRe9rFR9duev1ejCUwZARmCNPYzmt6wb1juS6VWiDYhJbSdCBYBfRDDMJuCSQx4nwH8S6RarZM1hv2g7xuMySFa2MBfaf94bdyrDmUSADzsenKves2MuBNpbK5nDDxEcEQ37ycRLrC9E2te7TgfLCS9EBvGxorS2KPRdYqWVJ44Eu59R643WAX6H4LGUL3K49okDPSZkvDesA2jZrZ")
const salt = bs58.decode("QdCCRE9UUxk5mvibicRN5L")
const nonce = bs58.decode("7S6GafTc7UQGhwTM7FcpcCVEUBAUtzG6g") const iterations = 100000
const key = await deriveEncryptionKey("test-passoword", salt, iterations, "sha256")
const plaintext = secretbox.open(encrypted, nonce, key);
if (!plaintext) {
throw new Error('Incorrect password');
}
const decodedPlaintext = Buffer.from(plaintext).toString(); console.log("Seed Phrase Below")
console.log(decodedPlaintext)
const { mnemonic, seed, derivationPath } = JSON.parse(decodedPlaintext);
if (stayLoggedIn) {
if (isExtension) {
chrome.runtime.sendMessage({
channel: 'sollet_extension_mnemonic_channel',
method: 'set',
data: decodedPlaintext,
});
}
else {
sessionStorage.setItem('unlocked', decodedPlaintext);
}
}
Press enter or click to view image in full size
VSCode at wallet-seed.js with modified code.

At this point you are almost done, you have the modified function and all the information you need to get the seed phrase. The last step I took was too add a call to the loadMnemonicAndSeed function in the LoginPage.js . This will allow the function to be called immediately upon starting sollet.io locally. Below is a screenshot of where to add the function.

Press enter or click to view image in full size
Line 36 is the function call.

All that is left is to run sollet locally, and look at the developer console to see the seed phrase. From my terminal I ran yarn start to start it locally. Then go to http://localhost:3000 to view your local instance. Open the developer console, and it should show an output similar to this. Obviously, I covered the mnemonic and account information.

{"mnemonic": bonus cancel head proud matrix hat erupt play network chimney arm spell popular damage wasp protect unit price view umbrella crime banana squeeze enemy}
Press enter or click to view image in full size
Screenshot of developer console.

From here you can stop the instance, go to sollet.io, and navigate to the restore existing wallet page.

Press enter or click to view image in full size
sollet.io restore wallet

Congratulations, hopefully you have recovered your wallet and funds. :)

P.s: Write your seed phrase down, seriously.

Add me on discord if you have more questions Renfis#5120 (renfeee since the discord changes)

If you want to donate, here’s an address: 4YRwCziLLhzx65vHtNJjWt3n6yvWknufEonuCzySxcyR ❤

--

--

Responses (11)