It started with a VPN problem
The other day, I had an issue with my VPN and someone from the IT service remotely connected to my machine to put a certificate on it. While he manipulated the certificate manager, he exported a certificate and typed a password of 4 characters that I couldn’t see (characters were obfuscated). Just after that he requested me to use another wifi connection to test the VPN so we had to stop the chat and the remote session. Unfortunatly for me it didn’t work and the guy went to lunch.
So now, I was stuck with no VPN and a certificate which were not working! I decided to delete all the personal certificates having my name from my computer and to re-import the p12 file that the IT guy left on my desktop. I tried to do so but then I was requested to type the password – remember? it was only 4 chars. I tried all the stupid 4 letters password I got in mind (“test”, “1234”, “0000”, “aaaa”, “azer”, “qwert” …) but none of them worked.
Let’s brute force that weak p12 password
So here is the interesting part. I decided to try that very famous thing called “brute force” a password. I was saying in my mind “With my years of programming experience, it should take me 10 minutes to code it and few second to run”.
But actually it took me up to one hour to make the stuff to actually work without obvious bug in C#:
private IEnumerable<string> EnumerateOptions(IList<char> options, int minLength, int maxLength) { var number = new List<int>(maxLength); for (int i = 0; i < minLength; i++) number.Add(0); while (number.Count <= maxLength) { yield return Stringify(number, options); bool overflowed = true; for (int numberPart = number.Count - 1; numberPart >= 0 && overflowed; numberPart--) { number[numberPart]++; if (number[numberPart] >= options.Count) { number[numberPart] = number[numberPart] % options.Count; } else { overflowed = false; } } if (overflowed) number.Insert(0, 0); } } private string Stringify(IList<int> number, IList<char> options) { return string.Join("", number.Select(n => options[n])); }
The result
The app was testing 2k passwords per seconds and found the password in less than 3 minutes 🙂 !
The conclusions are
- don’t use a 4 letters password, obviously, especially on your p12 files which can used to act on your behalf
- coding simple things can take more time than we expect (think hiring interview questions)
- The method I’m using to check the password (X509Certificate2Collection.Import) throws an exception when the password is wrong. This makes the process extremelly slow (15x). When you happen to completely ignore the exception (catch(Exception) with a variable), it becomes reasonably faster if you activate the code optimization (Release mode)
That’s it, the code is on Github. If you happen to spot obvious bugs in the enumerator of passwords, don’t hesitate to let me know with a comment.