1

For my job I use some industry-specific software that stores sensitive information. The software has a web interface with a public login page. One time I attempted to log in, but mistyped the last few characters of my password. To my surprise it let me in anyway. This started me down the rabbit hole of how the password was being stored.

After some investigation and reverse engineering, it appears the password is stored in the database as a 10 digit integer with a custom hashing method. The hashing method is roughly as follows:

  1. Remove surrounding whitespace from password
  2. If password is less then 10 characters then insert some predefined padding characters at a position determined by the original length
  3. Discard all but first 10 characters of password
  4. Remove repeated characters (aabbaabb becomes abab)
  5. Remove special characters
  6. Replace each character with a corresponding number from a lookup table
  7. Append predefined numbers to the end if less than 10 characters long
  8. Convert to an integer
  9. If the first character in the original password is a special character then multiply by -1

Obviously this leaves a lot to be desired. I have contacted the vendor, although they don't appear to share my concern.

An online attack isn't practical due to being locked out after several password attempts. It's trivial to find working password candidates given the hash, although due to the amount of discarded information I can't see a guaranteed way of finding the original password.

Am I right in being concerned? What issues could this potentially cause?

3
  • Name and shame? This is one of the worst I've seen and I've seen a few... May 10, 2022 at 17:11
  • 2
    What blows me away most of all is that any programming framework will have all the hashing primitives you need built in or easily available . So not only is this embarrassing, it wasn't even cost effective to start with. May 11, 2022 at 8:56
  • 1
    @BrunoRohée It appears password hashing is the least of their security problems. I've found a couple of login exploits/backdoors that bypass the password check entirely. There's also a bug with their file management utility that allows me to dump system files. I'm pretty sure there's a remote code execution vulnerability too, but I haven't got a working proof of concept for that yet. May 11, 2022 at 17:46

1 Answer 1

5

Wow, that was excruciating to read. The vendor should be deeply ashamed.

Am I right in being concerned?

Yes. That's phenomenally bad design. To make matters worse, there is simply no excuse whatsoever for doing this. A simple single round of MD5 salted with the user's name - while a terrible password hashing scheme already - would be absurdly more secure than this. The bcrypt password hashing function is over 22 years old - even the latest purpose-build password hashing function, argon2, is at least six years old - and they're supported in every language of significance. There's just no excuse for being this sloppy.

What issues could this potentially cause?

  • Some passwords collapse to the empty string (before padding). For example, the password )*?&#Q,%.$&^]! is equivalent to the empty string.
  • Even passwords that don't collapse to empty string are way, way weaker than they should be. nnnnnnnnnnnn is a bad password, but it's a heck of a lot harder to guess than n (or nn, or nnnnnn, or... you get the idea).
  • For all passwords, you get a ton of collisions due to mapping a 62-value (case-sensitive alphanumeric) character set onto a ten-value (digits) character set.
  • The truncation you noted is a huge problem, especially for credential stuffing attacks. Many people use one "strong" password across many sites, possibly with minor variations (e.g. the site name) added such that it's not technically repeated. If the base password is long enough and the variation is at the end, it will be lost entirely. Similarly, many people use multiple-word diceware-style passphrases (think XKCD's "correct horse battery staple"), where each character add very little entropy but the overall length makes it quite strong anyhow; severely truncating the length renders it barely more than a dictionary word.
  • As you noted, brute-forcing the "hash" is trivial, so anybody who gets read access to the database (directly, or by obtaining e.g. a backup image) can easily find a valid password for any and every user.
  • It's not even secure against rainbow tables - which can trivially be achieved by using a unique salt for each user - so if an attacker did want to try finding the original password, they could pre-compute the "hash" for billions of candidate passwords very quickly, and find at least one likely match for probably every possible "hash" value (which could then be used for credential stuffing or social engineering attempts elsewhere).
  • A bunch of this stuff - lookup tables, the negation thing, the padding, etc. - seem like they're designed under the assumption that nobody will know how the system works. As you've demonstrated, that's a terrible assumption in practice; people can and will reverse your code to figure it out. Such assumptions violate Kerckhoffs's principle, considered a fundamental feature of secure cryptosystems. Such a violation casts extreme doubt on the security of all code written by this developer. It's a red flag that they just don't know what they're doing (of course, the failure to simply use an established password hashing algorithm already raised that flag; this just puts it higher.)

Beyond that, I'd be worried about their anti-brute-forcing. It's easy to maliciously lock out a large number of legitimate users if the protection is too strict, either by getting their account locked or by getting their IP blocked (especially users behind carrier-grade NAT). Furthermore, if their lockout counting is vulnerable to race conditions (many are), a coordinated attack from a botnet could brute-force passwords from the outside anyhow.

1
  • Thanks for the detailed explanation! I've spent a bit more time on this and found even more problems. The lookup table is nowhere near a uniform distribution - 2 maps to 20 characters but 9 only maps to a single character. 2 and 5 combined account for over 50% of all characters and all but one vowel. A look at the database shows it's even worse with 2 appearing over 400 times and 9 appearing twice in the same sample. Oh, and in the 100 users I looked at there were multiple collisions! I've also found a few passwords that when used cause the account to be unable to log in. Fun. May 8, 2022 at 14:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .