Password shucking is a method of stripping layers off an updated password hash, removing the benefits of its new password hashing algorithm and reverting it to its weaker algorithm. Password shucking can be used by an attacker against old rehashed passwords or pre-hash passwords, enabling them to strip away or “shuck” off the strong outer password hashing algorithm.
In this article, I’m going to walk through the theory of password shucking. I initially struggled with understanding password shucking, so this is my take in explaining it. If you prefer a different style, I recommend checking out the DEFCON talk from Sam Croley (aka Chick3nman), which is embedded at the end of this article.
Combining password hashing algorithms: pre-hashing and rehashing
First, let’s take a look at why you might pre-hash or rehash a password.
When migrating password hashing algorithms, a common technique is to rehash all your existing password hashes using your new password hashing algorithm. This gives your users the protection of the new password hashing algorithm, without the need to reset everybody’s password or wait for them to re-authenticate, like with a rolling migration.
Rehashing old PBKDF2 hashes with Argon2id would mean that your password hashing algorithm would become the following:
This means that you have multiple layers to your password hashing algorithms: an outer layer of Argon2id (your new algorithm) and an inner layer of the weaker PBKDF2 (your old algorithm).
Pre-hashing is a technique used in some bcrypt implementations to bypass bcrypt’s max input limit of 72-bytes. This involves pre-hashing the plaintext password with something like SHA-384 before you pass it to bcrypt, ensuring that all passwords fall under the 72-byte limit.
This means that you have multiple layers to your password hashing algorithms: an outer layer of bcrypt (your password hashing algorithm) and an inner layer of the SHA-384 (your pre-hashing algorithm).
The idea behind bcrypt pre-hashing is that you can allow users to take advantage of very long passwords, rather than setting a max-size limit or truncating their password. In some bcrypt developer libraries, you’ll see pre-hashing listed as “Enhanced Entropy”.
The danger of password shucking
The problem with pre-hashing and rehashing is that if your inner hash does not use a salt and uses a fast hashing algorithm (e.g. MD5, SHA-1, SHA-256, etc.), then you are now vulnerable to a technique called password shucking.
Let’s say you are in the unfortunate position of having old, unsalted, SHA-1 password hashes, and you want to move to bcrypt. You rehash your existing hashes and now have a password hashing algorithm of:
Great, you’ve now protected those old passwords, and you’ve got some breathing room in the event of a breach.
However, using password shucking, an attacker can effectively strip (shuck) the use of bcrypt.
To shuck a password, the attacker relies upon two things:
- The target user appears in existing breaches that used your old password hashing algorithm
- The target user has re-used passwords across websites.
Using our example of bcrypt and SHA-1, the attacker will search old database breaches that contain unsalted, SHA-1 password hashes, looking for their target user.
With some SHA-1 hashes in hand, they can run that hash directly against the bcrypt hash:
If one of these hashes validate against the bcrypt hash, then the attacker no longer has to be concerned with bcrypt. They know the inner SHA-1 hash, so now they only need to crack that, which will be significantly faster than cracking a bcrypt hash. They have effectively stripped the outer layer (bcrypt). This is password shucking.
In his 2020 DEFCON talk, Sam Croley uses the example of bcrypt and MD5. Attacking the bcrypt layer directly with hashcat would only allow you around 2,000 guesses per second. Attacking the known MD5 hash, discovered using password shucking, would enable you 64,000,000,000 guesses per second.
The attacker even has the option to skip cracking the password themselves, as it may be a hash with a known plaintext (it is unsalted after all).
Should you pre-hash passwords or rehash?
Password shucking shouldn’t stop you from rehashing when migrating from an old password hashing algorithm. If you are using something like MD5 or SHA-256 (salted or not), you need to migrate to something better, and the threat of password shucking should not stop you.
Don’t forget that password shucking requires a user to re-use a password across websites (unfortunately, this is highly likely) and for an attacker to target individual users. As a herd immunity, I think rehashing alone will still help.
As with any rehashing approach, you should still only support the old or rehashed password hashes for a short amount of time. As each user successfully authenticates into your system, update their password hash to the new algorithm without the inner, legacy hash. Support rehashing for a limited amount of time (let’s say 3 months) and then delete any old style password hashes from your database. Those users who did not use your system in the rehashing window will instead have to reset their password.
To further improve things, you could include a pepper when you rehash the old password hashes. Just remember that the pepper must be kept secret, ideally stored away from your database and app in a key vault or HSM.
Should you pre-hash passwords?
No, not if you are pre-hashing with an unsalted, fast hashing algorithm. If you pre-hash, then your password hashing algorithm’s security is drastically reduced due to the risk of password shucking.
Recording: What the Shuck? Layered Hash Shucking
If you want to learn more about password shucking, check out Sam Croley’s (aka Chick3nman) original DEFCON talk: “What the Shuck? Layered Hash Shucking”.
A big thank you to Sam Croley for the technical review of this blog post.