Verify a user’s password in Linux

Verify a user's password in LinuxVerify a user's password in Linux

Linux does not store any plain password. It only stores hashes of passwords in a file called the shadow file. That makes cracking passwords more difficult by the contrast of ancient versions of Windows in which raw passwords were stored in the system registry. Needless to state, the content of this post is purely educational to get familiar with the basics of password hashing and not aimed to crack passwords. This article focuses on how to verify a user’s password in Linux.

If you do not want to read the entire article, you can watch the YouTube video instead.

As stated earlier, password hashes live in the shadow file that is under the /etc/shadow path. Let’s open the file and see its content first,

$ sudo cat /etc/shadow

The content of the file should look something similar like this,

daemon:*:18638:0:99999:7:::
bin:*:18638:0:99999:7:::
sys:*:18638:0:99999:7:::
sync:*:18638:0:99999:7:::
games:*:18638:0:99999:7:::
man:*:18638:0:99999:7:::
lp:*:18638:0:99999:7:::
mail:*:18638:0:99999:7:::
news:*:18638:0:99999:7:::
uucp:*:18638:0:99999:7:::
proxy:*:18638:0:99999:7:::
www-data:*:18638:0:99999:7:::
backup:*:18638:0:99999:7:::
list:*:18638:0:99999:7:::
irc:*:18638:0:99999:7:::
gnats:*:18638:0:99999:7:::
nobody:*:18638:0:99999:7:::
systemd-timesync:*:18638:0:99999:7:::
systemd-network:*:18638:0:99999:7:::
systemd-resolve:*:18638:0:99999:7:::
_apt:*:18638:0:99999:7:::
messagebus:*:18638:0:99999:7:::
_rpc:*:18638:0:99999:7:::
statd:*:18638:0:99999:7:::
sshd:*:18638:0:99999:7:::
avahi:*:18638:0:99999:7:::
lightdm:*:18638:0:99999:7:::
rtkit:*:18638:0:99999:7:::
pulse:*:18638:0:99999:7:::
saned:*:18638:0:99999:7:::
hplip:*:18638:0:99999:7:::
colord:*:18638:0:99999:7:::
systemd-coredump:!!:18638::::::
test:$6$OXE8gHwh2.nmuwp7$lrs3VWJiL9bFG0HRjtSWI3T7hbQOIVOA8GewwM7nPaZKy7TXtiD/pKoEM.pQvR9NNpnZyP2qhCrsvVf1NJEFl/:18661:0:99999:7:::

Now we want to verify the password of the test user. The assumption is we have a couple of passwords in mind. What we must do next is to generate the hash of the passwords we think are correct. Then compare the generated hashes with the one in the shadow file and see whether it matches. The hashing algorithm we select must match with the one in the shadow file.

How to find the hashing algorithm?

Each hash string has a hashing algorithm signature at the beginning between $ values. In this case, we have $6$ that indicates the used algorithm was SHA-512. You can find the signature list from this link. Additionally, the string between the second $ and third is the salt of the password. A salt is random data that is used as an additional input to hash a password. Salts are used for safeguarding passwords in storage (from Wikipedia).

The exact password hash is between the third $ and /: character. In our example, the password hash is lrs3VWJiL9bFG0HRjtSWI3T7hbQOIVOA8GewwM7nPaZKy7TXtiD/pKoEM.pQvR9NNpnZyP2qhCrsvVf1NJEFl.

Generate the hash

Now that we have figured out the hashing algorithm, let’s generate the hash for the passwords we have in mind.

There are multiple ways to generate a hash of a specific string. Here we cover two:

  • Using the mkpasswd command
  • Programmatically with Python

Mkpasswd command

The command may not exist in your Linux machine. So make sure to install it. On Debian-based distros, the mkpasswd is a part of the whois package. You can install it as follows,

$ sudo apt install whois

To generate a hash, we have to run the mkpasswd like this,

$ mkpasswd -m [algorithm] [password] [salt]

Hence we have,

$ mkpasswd -m SHA-512 test1234 OXE8gHwh2.nmuwp7

Note that I did not pass $ as a part of the salt. It is unnecessary.

The output should be the hash,

$6$OXE8gHwh2.nmuwp7$lrs3VWJiL9bFG0HRjtSWI3T7hbQOIVOA8GewwM7nPaZKy7TXtiD/pKoEM.pQvR9NNpnZyP2qhCrsvVf1NJEFl/

As you can see, we guessed the password correctly, and the real password is test1234 🙂

Using Python

The second approach is to use Python. That is very useful if you are looking for more flexibility and planning to add some custom codes, such as reading passwords from a database or an S3 bucket.

To generate a hash in Python, we can rely on a built-in library called crypt. It works straightforwardly. Have a look at the below code snippet.

import crypt

# usage: crypt.crypt("password", "hasing algorithm + salt")
print(crypt.crypt("test1234", "$6$OXE8gHwh2.nmuwp7$"))

# sample output: $6$OXE8gHwh2.nmuwp7$lrs3VWJiL9bFG0HRjtSWI3T7hbQOIVOA8GewwM7nPaZKy7TXtiD/pKoEM.pQvR9NNpnZyP2qhCrsvVf1NJEFl/

As you can see, we did not explicitly specify the hashing algorithm in the crypt function. We just passed the values between $ that includes hashing algorithm signature and the salt, then let the code figures out the rest.

That’s all on how to verify a user’s password in Linux. I hope you enjoyed it.

Inline/featured images credits