Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement password or seed bruteforcer #1035

Closed
nopara73 opened this issue Jan 3, 2019 · 22 comments
Closed

Implement password or seed bruteforcer #1035

nopara73 opened this issue Jan 3, 2019 · 22 comments

Comments

@nopara73
Copy link
Contributor

nopara73 commented Jan 3, 2019

Mistyping the password or forgetting one seed word is a common occurence. According to Electrum's developer @spesmilo it is more common than wallet hacking (Building on Bitcoin talk.)

So it may be a good idea to add a small brute forcer to the software that helps these users recover their funds.

@Transisto
Copy link

Transisto commented Jan 3, 2019

Sad but would wait for a specific use case/event to develop something and would definitely not make it part of the wallet.

Forgetting one word mean about 24 000 permutations.

How strong is the password added to the 12 word seed?
If it's anywhere as strong as BIP38 I think it's very long to bruteforce even a 4 characters password.

I have no current specific improvement suggestion but these would be easier to mitigate with improved wallet creation assistance UX than after the fact.

@nopara73
Copy link
Contributor Author

nopara73 commented Jan 3, 2019

Now thinking about this the mnemonic seed recovery would be unfeasible, because Wasabi doesn't index the chain and in order to recover your words Wasabi should check that, which would result downloading a block or two for every combination.

Password typo correction is still good though.

would wait for a specific use case/event

Check: https://old.reddit.com/r/WasabiWallet/comments/aby0de/password_problem/

@Transisto
Copy link

Transisto commented Jan 3, 2019

In that reddit situation it doesn't seems like a messed up seed. If you meant that bruteforcer would need to seek balanced for every iteration of a missed word, I don't think so. In most case the receiving address would be know and it would only need to derive and verify a match of the first receiving address.

Although hard to quantify, having a bruteforcer anywhere near the wallet weaken security during normal uses. An example would be a relative that knows what password theme you might use and be helped to break an already weak password.

If a brute-forcer is developed it would be better bundled independently and have as only link to Wasabi the public knowledge of it's derivation path and encryption schemes.

If I wasnted to build such a tool I think I'd start here for code samples : https://iancoleman.io/bip39/

@nopara73
Copy link
Contributor Author

nopara73 commented Jan 3, 2019

In that reddit situation it doesn't seems like a messed up seed.

It doesn't, but if we're implementing a restore-ability then let's implement it comprehensively. That being said, there was another thread were the guy lost one mnemonic word: https://old.reddit.com/r/WasabiWallet/comments/a5707n/any_help_will_be_greatly_appreciated/

In most case the receiving address would be know and it would only need to derive and verify a match of the first receiving address.

That's an interesting hack, I didn't think of. Maybe we can work with it.

An example would be a relative that knows what password theme you might use and be helped to break an already weak password.

A typo correcter is not useful for this, unless you know your victim's password in the first place, but you suspect she made a typo, which is just silly:)

@nopara73
Copy link
Contributor Author

A user needed this feature, so I created a small command line tool that could be a good starting point for this issue in the future: https://github.com/nopara73/WasabiEncryptedSecretTester

@lontivero
Copy link
Collaborator

The problem that I see here is that we use bip38 to encrypt the wallet and it uses scrypt as key derivation function, an algorithm specially designed to make brute force attacks very expensive, what can slow down each attempt enough for making the procedure useless. In fact I think that for breaking a 10 letters password you need to sacrifice a good part of your life waiting.

@nopara73
Copy link
Contributor Author

nopara73 commented Jan 26, 2019

@lontivero That's why it'd only be useful for a user and not for an attacker. He made a typo, doesn't remember one letter, or which letter it has capitalized or the number he used at the end, etc...

@lontivero
Copy link
Collaborator

lontivero commented Jan 26, 2019

Confirmed. In my machine (intel i7) running at 80% all the time it takes 00:07:36 for 1000 attempts (0.456 seconds/attempt). So, following these numbers, and taking into account that a very weak 8 characters password has 3025989069143040 possible combinations.

This means that 1512994534571520 attempts would require in my machine 21877394 years.

Try this:

internal class Program
{
    private static void Main(string[] args)
    {
        var encryptedSecret = new BitcoinEncryptedSecretNoEC("6PYSeErf23ArQL7xXUWPKa3VBin6cuDaieSdABvVyTA51dS4Mxrtg1CpGN");

        var sw = new Stopwatch();
        sw.Start();
        foreach(var attempt in Enumerable.Range(0, 10_000))
        {
            try
            {
                if(attempt > 0  && attempt % 1_000 == 0)
                    Console.WriteLine($"{attempt} attempts in {sw.Elapsed}");
                encryptedSecret.GetKey("password");                    
                return;
            }
            catch (SecurityException)
            {
            }
        }
        sw.Stop();
        Console.WriteLine($"Completed in {sw.Elapsed}");
    }
}

Results:

$ dotnet build -c Release
$ dotnet WasabiEncryptedSecretTester/bin/Release/netcoreapp2.2/WasabiEncryptedSecretTester.dll
1000 attempts in 00:07:38.7655032
2000 attempts in 00:15:09.2643941
3000 attempts in 00:22:46.2276900
4000 attempts in 00:30:25.2294415

4000 attempts in 30 minutes! Of course NBitcoin is not optimized for this but in any case brute forcing wallets is not so easy, what is something pretty good IMO.

UPDATE: I didn't read your previous comment before commenting. I will do the numbers then and see if this can be possible in some scenario.

@lontivero
Copy link
Collaborator

I have done some calculations just to know how feasible this idea is based on the following use cases:

  • User made a mistake in one and only one letter. This includes all possible combinations of only one error (user forgot what letter capitalized, one typo, one replacement of A by 4, E by 3, L by 1 and other similar)

We assume the user's password contains only English letters (uppercase and lowercase), numbers and punctuation symbols. According to this there are 95 characters. So, taking 14 length password, if we need to check letter by letter we have: 14 * 95 = 1330 passwords..

Based on my test, a more or less decent computer can calculate 4 passwords in 3 seconds so, 1330 passwords could be solved in 1330 * 3 /4 = 997.5 seconds (16 minutes in the worst case). In average it takes 8 minutes.

This seems to be feasible except for passwords with multiple errors (like those introduced with CapsLock enabled), long passwords (len(password) > 30) or passwords with ñ, é, ü and others.

Taking into account that this is a very heavy CPU process i think it could be good to throttle the process just a bit. Also, a machine without a decent amount of memory could need to swap and in that case this process could take much more time.

The following code is an example that finds, by brute forcing, teh password with one error. It uses a reduced set of characters.

    internal class Program
    {
        private static char[] chars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@$?_- \"#$%&()=".ToArray(); 
        private static void Main(string[] args)
        {
            var password = "MariaN3llA&";
            var encryptedSecret = new BitcoinEncryptedSecretNoEC("6PYL1uxQPXwNV6BMruXaSbAcpBEDPuA8biUfvy3g1vc8V54t5rn4f6Z1na");

            var sw = new Stopwatch();
            sw.Start();
            var pwChar = password.ToCharArray();
            for(var i=0; i < pwChar.Length; i++)
            {
                var original = pwChar[i]; 
                Console.WriteLine($"Trying position {i}");
                foreach(var c in chars)
                {
                    pwChar[i] = c;
                    var newPassword = new string(pwChar); 
                    try
                    {
                        encryptedSecret.GetKey(newPassword);
                        Console.WriteLine("Password found: " + newPassword);
                        goto end;
                    }
                    catch (SecurityException)
                    {
                    }
                }
                pwChar[i] = original; 
            }
            end:
            sw.Stop();
            Console.WriteLine($"Completed in {sw.Elapsed}");
        }
    }

The result is quite acceptable (6 minutes):

$ dotnet WasabiEncryptedSecretTester/bin/Release/netcoreapp2.2/WasabiEncryptedSecretTester.dll
Trying position 0
Trying position 1
Trying position 2
Trying position 3
Trying position 4
Trying position 5
Trying position 6
Trying position 7
Trying position 8
Trying position 9
Password found: MariaN3ll4&
Completed in 00:05:44.6723129

This could be made faster and less cpu aggressive by increasing the memory required. This can be done by modifying NBitcoin's Scrypt memory parameters.

@lontivero
Copy link
Collaborator

I think we could close this issue now.

@nopara73
Copy link
Contributor Author

nopara73 commented Feb 11, 2019

This should make its way to the GUI and also be more customizable there than it is currently.

@lontivero
Copy link
Collaborator

Ack. What kind of customization do you have in mind?

@lontivero
Copy link
Collaborator

Btw, I've gave an overview to this research paper and there is nothing on it that we can use, basically because it talks mostly about "relaxed passwords checkers" what is not applicable in Wasabi. I was also making a quick online research about the Levenshtein distance (that someone suggested on twitter) but it is useful with dictionaries what is not useful here neither.

@Transisto
Copy link

Transisto commented Feb 14, 2019 via email

@nopara73
Copy link
Contributor Author

There is nothing anti-secure about this feature: refer to the whole conversation in this thread. It may create a sense of anti-security, but such feelings should not prevent a useful feature to get into the software.

@Transisto
Copy link

Transisto commented Feb 14, 2019 via email

@nopara73
Copy link
Contributor Author

I'm sorry, but I don't see how that would make sense. The person using it

  1. has to think he knows the password
  2. has to have access to the wallet file
  3. has to guess the possible typos he could've made (from @lontivero's numbers above we can see that we cannot do generic typo fixing with this, but it must be configurable, generic typo fixing would take years)

@nopara73
Copy link
Contributor Author

nopara73 commented Feb 14, 2019

Most people who lose their passwords don't open issues or post to reddit, because they think there's nothing to do about it. If it's not in the software they lose access to the wallet, they are not aware of the compulsory tool we made, they acknowledge it and go on with their life.

You are referring to infeasible theoretical attacks while in practice people all over the world losing money.

@nopara73 nopara73 mentioned this issue Feb 23, 2019
11 tasks
@mikeborghi2
Copy link

Just saw this post and thought i'd chime in.

First off

  1. it'd be great to have the derivation scheme documented in a more accessible place if it isn't already (I couldnt find all the details but could probably guess after going into the source code).
    With projects in the bitcoin space often dying out as new solutions emerge, its important to have resources for people to get their coins from legacy wallets.

But assuming the wallet abides by the bip39 standard, there is a tool in this repo https://github.com/gurnec/btcrecover made exactly for guessing a mistyped phrase thats off by a word or two. I don't know exactly how the specifics of Wasabi's derivation scheme change it
Seed Recovery Guide
https://github.com/gurnec/btcrecover/blob/master/docs/Seedrecover_Quick_Start_Guide.md

It works by building the utxo set of the network (which will be a large file) then upon each seed guess iteration, it checks to see if an address derived from the seed has utxo's. however, i'm not 100% this can be done with how wasabi handles addresses but i figured this information is worth posting

@nopara73
Copy link
Contributor Author

nopara73 commented Mar 13, 2019

@mikeborghi2 Actually the next version has an advanced info tab so I think that'll suffice your concerns:

image

But assuming the wallet abides by the bip39 standard

It does, except on the testnet, for testnet, mainnet paths are used. We only support one coin in this sense: Bitcoin. This is because our keymanager is network agnostic.

@Transisto
Copy link

Most people who lose their passwords don't open issues or post to reddit, because they think there's nothing to do about it.

I'd think most people know they can try another password so instinctively that they could eventually find the right one.

That tool looks very complete and support the same derivation scheme as Wasabi.

Should that issue be closed and be replaced by a FAQ style explanation suggesting options like btcrecover?

@nopara73
Copy link
Contributor Author

It's added to the daemon. I guess we'll stop halway here and everyone is happy (or not.)

IMO the UI is getting way too feature rich, so that's my reason #1 why we may shouldn't have it in the UI after all.
Reason #2 is that we seemed to have stopped password loss issues with the various implementations of our "Lost Password Strategy" zkSNACKs/zIPs#44

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants