OpenSSL passwd (crypt, MD5, APR1, SHA256 and SHA512) with salt
[OpenSSL Home][Home]
In this case we will generate hashed passwords in different formats, and using a salt value. The methods are implemented with OpenSSL, and include crypt, APR1, SHA512 and SHA256. Note that the salt value is defined in a Base-64 format, and where we have 96 bits of salt that can be used for SHA256 and SHA512 format, while 48 bits are used for APR1.
|
Outline
The use of passwords first started at the Massachusetts Institute of Technology (MIT) and allowed multiple people to share the use of a mainframe computer. But, soon, we had the first "hacker", and where Allan Scheer found a way to print out the password list and "hack" the system. It took until 1970 for Robert Morris to translate a password into an encrypted form, and which limited the opportunities for someone to discover the password. At the time, it was not possible to reverse back the encrypted form back into the password.
Morris worked on the Unix operating system at Bell Labs and coded the crypt password encryption method (and invented by Roger Needham). With this, a hashed version of the password is stored in the /etc/passwd file on the system. You may know of the name "Morris" from the infamous Morris worm. This was actually created by Robert's son (Robert Tappen Morris), and which was the first computer worm (1988). At the time, his son was the first person to be convicted under the Computer Fraud and Abuse Act (CFAA). Unfortunately, the Morris worm caused large-scale damage to systems across the Internet, and which generally took over the CPU time, and typically crashed the system.
OpenSSL
And, so, the first version of the storing a password securely as the crypt method. With normal encryption method, we encrypt our data with a key. But with crypt, we use the password as the key and use this to encrypt the password. Unfortunately, the crypt method was then found to be too fast, and thus allowed the hash password to be easily broken by brute force.
An enhancement then used the DES encryption method. One problem was then, that once the hashed version was discovered, it was cracked for all occurrences of that password. This led to the creation of rainbow tables for crackers, and where large databases could be created which mapped a password to a hashed value. And so a salt value was added (either before or after then password) to the password before it was hashed, and which resulted in differing hashed values for the same password. With the knowledge of the salt value, and the password, it was possible to generate the hash encrypted form.
These days, crypt has been removed in many applications, as it can be easily cracked (as with the DES encryption method - due to its relatively small encryption key). Now let’s try for "Hello" and a salt value of "241fa86763b85341:
openssl passwd -crypt -s 241fa86763b85341 Hello Word: Hello Method: -crypt Salt: 241fa86763b85341 24dw4/Mam3sLc
If we try "111111111", we get:
openssl passwd -crypt -s 111111111 Hello Word: Hello Method: -crypt Salt: 111111111 11GMhubChLGxM
and "123456":
openssl passwd -crypt -s 123456 Hello Word: Hello Method: -crypt Salt: 123456 12AuwdSPXuQnc
What we see is that most of the salt is ignored, and where only the first two characters are used for the salt value. This can be tested with:
openssl passwd -crypt -s 12 Hello Word: Hello Method: -crypt Salt: 12 12AuwdSPXuQnc
And which gives the same hashed value. We can thus see why crypt should not be used, and which has been deprecated by OpenSSL 3.0.
Once hashing methods were developed, the natural focus became the usage of the MD5 hashing method. For this Poul-Henning Kamp created a method which allowed any length of the password to be converted into a hashed password. In OpenSSL, we use the "-1" option:
openssl passwd -1 -s 1234567890 Hello Word: Hello Method: -1 Salt: 1234567890 $1$12345678$pXsdVOIgvj7gmTb3pUCW9/
We can see in this case, that we now have the "\$" symbols to break up the hash. The value of "\$1\$" identifies the MD5 method, "12345678" defines the salt value used, and the rest is the hash ("pXsdVOIgvj7gmTb3pUCW9/"). We can see that using "12345678" produces the same hashed value:
openssl passwd -1 -s 12345678 Hello Word: Hello Method: -1 Salt: 12345678 $1$12345678$pXsdVOIgvj7gmTb3pUCW9/
Using "1234567", we get a different hash function:
openssl passwd -1 -s 1234567 Hello Word: Hello Method: -1 Salt: 1234567 $1$1234567$AwLojMJlUGmX9.4tqa1Ws0
But, we shouldn’t use this version, as it is fairly easy to crack with MD5, as it is a fast hashing method. What we need is a slow method of generating the hashed value, and one of the main methods is to use a number of rounds. This creates a sequential operation, and which will disable any kind of parallel processing operation — such as with the use of GPUs.
One of the first methods for this is was the APR1 function:
openssl passwd -apr1 -s 12345678 Hello Word: Hello Method: -apr1 Salt: 12345678 $apr1$12345678$lKtjSygR2codplxge95Ih/
This gives us 48 bits of salt (as we use a Base-64 format for the salt - and where each Base-64 character represents six bits) and uses 1,000 rounds. We thus take the input and the salt value and hash it with MD5 for 1,000 rounds to get the result. This breaks GPU cracking, as we cannot apply parallel processing methods. The salt value is still fairly small, and the MD5 hashing method is flawed, and so enhanced methods now use SHA-256 (with an option of "-5"):
openssl passwd -5 -s 123456789ABCDEFGH Hello Word: Hello Method: -5 Salt: 123456789ABCDEFGH $5$123456789ABCDEFG$3lMYxgcc0V32/37GU1swB2xnnOPRLSFkK0mATbyrzW3
We can now see the salt value is much greater, along with the length of the hash. With this we now have 96 bits of salt (eight Base-64 characters), and which will put it out of the bounds of cracking limits with a dictionary and for a search of salt values. The hash value is derived from SHA-256, and thus has 256 bits. If this is not secure enough, we can use SHA-512 with the "-6" option:
openssl passwd -6 -s 123456789ABCDEFGH Hello Word: Hello Method: -6 Salt: 123456789ABCDEFGH $6$123456789ABCDEFG$1kzUb7O8fpgD2MRd0cX0Be2LqwPlwp1ib4og4HgkT3eS230o.me2EduY0CPr1GUeU1kkLTAfn5HvxA5tpnzZS/
So, let’s look at an example of using the "-6" option.
Splunk passwords
Splunk is a great tool. Under the hood, it actually operates like a Linux type environment (even on a Windows OS). Each of the users are then stored in the passwd file in the etc folder, so for a user "csn01" we have:
:csn01:$6$Uk8SVGLsBuSmD75R$Lhp5yjwRUAM.LbH5IIthZ1u0bAUdJwBvvccBshAvpFPiRn62EYeiKOaP8xh97aV4UaNfVykRZhUy/3ZOZd1oc.:::user::::18161
So what is the method used for hashing the password? Well, we split the hashed password into three main groups (separated by the "$" symbol):
6 Uk8SVGLsBuSmD75R Lhp5yjwRUAM.LbH5IIthZ1u0bAUdJwBvvccBshAvpFPiRn62EYeiKOaP8xh97aV4UaNfVykRZhUy/3ZOZd1oc.
and where "6" is the hashing method (SHA-512), "Uk8SVGLsBuSmD75R" is the salt value, and "Lhp5yjwRUA..d1oc." is the hashed version of the password using 5,000 rounds. When the user logs into Splunk, their password will be added to the salt value, and the same hashed version should be created. Well, the "$6" part identifies that it is SHA-512, but when I try to hash with SHA-512, it gives the wrong hashed value. The answer lies in slowing the hashing process down by performing a number of rounds. For this 5000 rounds works to give the right result, and so here is the Python code [here]:
import passlib.hash; import sys; password="qwerty123" salt="Uk8SVGLsBuSmD75R" # csn01:$6$Uk8SVGLsBuSmD75R$ Lhp5yjwRUAM.LbH5IIth user="fred" h=passlib.hash.sha512_crypt.hash(password, salt=salt,rounds=5000) # Fred:$6$Uk8SVGLsBuSmD75R$Lhp5yjwRUAM.LbH5IIthZ1u0bAUdJwBvvccBshAvpFPiRn62EYeiKOaP8xh97aV4UaNfVykRZhUy/3ZOZd1oc. hash=user+":"+h print (hash)
A sample run:
===Splunk hashed password=== User: Fred Password: qwerty123 Salt: Uk8SVGLsBuSmD75R ===Hashed password Fred:$6$Uk8SVGLsBuSmD75R$Lhp5yjwRUAM.LbH5IIthZ1u0bAUdJwBvvccBshAvpFPiRn62EYeiKOaP8xh97aV4UaNfVykRZhUy/3ZOZd1oc.
and this matches the Splunk entry. With hashcat, the default is also 5,000 rounds. If we try, with the program on this page we also get the same result:
openssl passwd -6 -s Uk8SVGLsBuSmD75R qwerty123 Word: qwerty123 Method: -6 Salt: Uk8SVGLsBuSmD75R $6$Uk8SVGLsBuSmD75R$Lhp5yjwRUAM.LbH5IIthZ1u0bAUdJwBvvccBshAvpFPiRn62EYeiKOaP8xh97aV4UaNfVykRZhUy/3ZOZd1oc.
It should be see that the salt value is defined in a Base 64 format. If we now use Hashcat on the hashed version, we should be able to discover the original password:
root@kali:~# hashcat -m 1800 1.txt -a 0 /usr/share/wordlists/rockyou.txt Initializing hashcat v0.49 with 1 threads and 32mb segment-size... Added hashes from file 1.txt: 1 (1 salts) Activating quick-digest mode for single-hash with salt NOTE: press enter for status-screen $6$Uk8SVGLsBuSmD75R$Lhp5yjwRUAM.LbH5IIthZ1u0bAUdJwBvvccBshAvpFPiRn62EYeiKOaP8xh97aV4UaNfVykRZhUy/3ZOZd1oc.:qwerty123 All hashes have been recovered Input.Mode: Dict (/usr/share/wordlists/rockyou.txt) Index.....: 1/5 (segment), 3627172 (words), 33550339 (bytes) Recovered.: 1/1 hashes, 1/1 salts Speed/sec.: - plains, 461 words Progress..: 2172/3627172 (0.06%) Running...: 00:00:00:05 Estimated.: 00:02:11:03
In this case, we use the rockyou.txt list of common passwords, and where it only takes five seconds to find the password. The advantage of using SHA-512 with a number of rounds is highlighted when we run a benchmark:
root@kali:~# hashcat -b -m 1800 Initializing hashcat v0.49 with 1 threads and 32mb segment-size… Device………..: Intel(R) Core(TM) i7–8850H CPU 2.60GHz Instruction set..: x86_64 Number of threads: 1 Hash type: sha512crypt, SHA512(Unix) Speed/sec: 454 words root@kali:~# hashcat -b -m 0 Initializing hashcat v0.49 with 1 threads and 32mb segment-size… Device: Intel(R) Core(TM) i7–8850H CPU 2.60GHz Instruction set..: x86_64 Number of threads: 1 Hash type: MD5 Speed/sec: 17.33M words
In this, hashcat can process 454 words per second with SHA512crypt and over 17 million per second with MD5.