Digging Into Password Storage in DotNetNuke
On 31st of May I received an email from Scrum.org notifying me that they suffered a data breach on or before the 26th May. I’ve included the important part of the breach notification email below.
What information Was Involved?
While we continue to investigate the matter, we have determined that user’s names, email addresses, encrypted passwords, the password decryption key, and completed certifications and their associated test scores may have been compromised, but at this time we are not able to confirm that any of these items were actually taken, nor is there any evidence that any of this information was used by an unauthorized individual. User’s profile photographs, if uploaded, may also have been compromised. We do not store any other information on our servers. No financial information was involved in this incident.
The mention of “encrypted passwords” and the “password decryption key” raised a couple of questions. When asked on Twitter if the passwords were salted, Scrum.org replied that they were salted, which left me a little confused.
Comments in the Scrum.org website indicated that they were using the open source CMS DotNetNuke, so I wanted to investigate how DotNetNuke stores passwords and how this could affect other users of this CMS.
Using Github search to find any occurances of the word password in the DotNetNuke repository gave me a good starting point, which is where I found the release.config file used to configure ASP.NET websites. The configuration section for the AspNetSqlMembershipProvider contains a setting to control the format used for password storage with a comment explaining the possible values:
passwordFormat="[Clear|Hashed|Encrypted]" Storage format for the password:
Hashed (SHA1), Clear or Encrypted (Triple-DES)
It seems odd that a well known CMS would offer any of these options for storing user passwords when it is widely known that passwords should be hashed using an algorithm specifically designed for protecting passwords. Storing passwords improperly is one of the vulnerabilities covered in the OWASP Top 10.
Some further investigation found CoreCryptographyProvider.cs. The EncryptString method is of interest, it uses the .Net Framework’s TripleDESCryptoServiceProvider to encrypt passwords using an MD5 of the passphrase as the key and is configured to use ECB (Electronic Codebook) mode, which was one of the contributing factors to the 2013 Adobe password leak. One of the main weaknesses with ECB mode, regardless of which algorithm it is used with, is that identitical plaintext blocks will encrypt to identity ciphertext blocks, allowing patterns to be identified from the ciphertext alone. For more details on the weaknesses of encryption using ECB mode, see this Cryptography StackExchange thread.
If a DotNetNuke instance is configured to use hashed passwords, then password storage is instead handled by the ASP Membership provider. This stores passwords as a salted hash and defaults to SHA1. It might seem that this is an improvement on Triple DES, but as has been demonstrated before by Troy Hunt, salted SHA1 hashes are incredibly weak to attack. To summarise, good cryptographic hash functions are very fast, good password hashing functions should be very slow (relatively speaking).
In order to remediate this issue, DotNetNuke should adopt a Key Derivation algorithm such as PBKDF2, bcrypt or scrypt. PBKDF2, which is part of the .Net Framework as Rfc2898DerviceBytes
, provides a good starting point for storing passwords and provides a tunable “work factor” to lengthen the time taken to compute one hash. Unfortunately, PBKDF2 requires very little memory which lends itself to GPU acceleration. The bcrypt algorithm is much more resistant to GPU attacks as it relies heavily on access to a constantly changing table of values, which is very inefficient on a GPU where all of the cores share the same memory. However, bcrypt was designed before the advent of FPGAs (Field Programmable Gate Arrays) with embedded RAM blocks,which solves the issue of each core requiring access to its own block of memory that limits a GPUs effectiveness. Scryptis designed to make this kind of attack as hard as possible by making the computation of a hash not only compute intensive, but memory intensive too.
PBKDF2, bcrypt and scrypt have their relative strengths and weaknesses, but when properly tuned, all are superior to storing passwords in an encrypted or SHA* hashed format. In order for DotNetNuke to make the transition to a more secure password storage mechanism easier for its users, passwords can be migrated to the new format over time as users log in. This doesn’t provide immediate increased security, but any accounts that haven’t been migrated after a certain period of time could have their passwords forcibly reset.