mkpasswd -m sha-512 produces incorrect login

I'm running into trouble trying to set passwords for my new users.

I found a tutorial indicating that mkpasswd -m sha-512 "my password here" would produce a salted and hashed password that can be used in combination with useradd -m -p "hashed and salted passwd" -s /bin/bash username, however when I tried this on a test user, I keep receiving Incorrect Login.

I am running Ubuntu 16.04 and using mkpasswd from the whois package.

What am I doing wrong here?


Exact Steps

1) apt update

2) apt install whois

3) mkpasswd -m sha-512 "my password here"

produces: $6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g.

4) useradd -m -p $6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g. -s /bin/bash testuser

5) login testuser

Prompts for password:

6) type my password here

Says: Login incorrect


Would like to add that I tried the same thing with a password that has no spaces, and omitted the quotes from the mkpasswd command. Neither seemed to make a difference.

I also tried to make the user without the -p flag (meaning don't add a password) and manually copied the salted/hashed password into /etc/shadow which produces the same results as above, Login incorrect.


Even more interesting, if I use a subshell to put the value in, everything seems to work fine.

useradd -m -p $(mkpasswd -m sha-512 "my password") -s /bin/bash test

login testtype: my password

Logs in just fine!

13

2 Answers

Okay, I locked down the issue. Since the output of mkpassword will result in $id$salt$hash, when you copy and paste this into a useradd command, bash will try and do variable replacement on the $. As such, those need to be escaped using \$id\$salt\$hash so that bash will not do variable replacement before adding the string to /etc/shadow.

mkpasswd -m sha-512 "my password"results in

$6$5AfGzrQ9u$r6Q7Vt6h8f2rr4TuW4ZA22m6/eoQh9ciwUuMDtVBX31tR3Tb0o9EB1eBdZ2L9mvT.pX3dIEfxipMoQ0LtTR3V1

which can be copied and pasted into useradd making sure to replace each $ with \$.

useradd -m -s /bin/bash -p \$6\$5AfGzrQ9u\$r6Q7Vt6h8f2rr4TuW4ZA22m6/eoQh9ciwUuMDtVBX31tR3Tb0o9EB1eBdZ2L9mvT.pX3dIEfxipMoQ0LtTR3V1

1

Why does this happen ?

The reason why it fails is because items with leading $ are treated as variable and are unquoted when you pass it to useradd.

The $6...,$1..., and $b... portions from your hash are treated as variable. Of course, the fault is with the shell - shells perform variable expansion (unless they're single-quoted ) before anything runs. And because those 3 variables don't exist in your environment they disappear from the string you pass to useradd.

Practical example:

Let's see what actual command runs after the shell finished performing all necessary expansions and substitutions and passed that to execve() system call. Compare:

$ strace -e execve useradd -p $abra$cadabra newuser
execve("/usr/sbin/useradd", ["useradd", "-p", "newuser"], [/* 82 vars */]) = 0
$ strace -e trace=execve useradd -p '$abra$cadabra' newuser
execve("/usr/sbin/useradd", ["useradd", "-p", "$abra$cadabra", "newuser"], [/* 82 vars */]) = 0

In the first example $abra$cadabra ( which is where your hash would go) disappears from the command that actually gets to run by the system. In contrast, the single quoted $abra$cadabra in the second example appears on the list of arguments that do get passed to execve().

In other words, you generated correct hash, but shell passes completely different thing to useradd as argument, which ultimately is the command that system runs. In fact, let's just take your hash for instance and compare two cases of quoting and non-quoting:

$ strace -e execve echo $6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g
execve("/bin/echo", ["echo", "FuuSdKgVke.LYTfrlknm5cWx65g"], [/* 82 vars */]) = 0
FuuSdKgVke.LYTfrlknm5cWx65g
+++ exited with 0 +++

Notice that what system actually sees after the shell is done processing the variables is FuuSdKgVke.LYTfrlknm5cWx65g. But it will see the correct hash if you quote it:

$ strace -e execve echo '$6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g'
execve("/bin/echo", ["echo", "$6$1FuuSdKgVke$bc8doOVGZhzomoeaf"...], [/* 82 vars */]) = 0

What can be done ? What works ?

However, subshell works because there is no replacement occurring - there's no variables. And quoting also works for the same reason.

Here are a few methods:

  1. Command substitution:

    $ sudo -p ">" useradd -m -s /bin/bash -p $(mkpasswd --hash=SHA-512 "123" ) newusr
    >
    $ su newusr
    Password:
    newusr@ubuntu1604:/home/admin$ 
  2. Single-quoting(note that I've trimmed actual hash because it's too long and doesn't fit into formatting):

    $ sudo -p ">" mkpasswd --hash=SHA-512 "112"
    >
    GVhvDY$vhw89D2X0bd2REQWE
    $ sudo -p ">" useradd -m -s /bin/sh -p 'GVhvDY$vhw89D2X0bd2REQWE' newusr2
    >
    $ su newusr2
    Password:
    $ echo $USER
    newusr2
  3. Take output from mkpasswd's stdout stream and pass it via xargs with -I flag:

    $ mkpasswd -m sha-512 'password1' | sudo -p '>' xargs -I % useradd -p % newuser1 
  4. Append \ to every $ (which OP figured out themselves in their answer). Scriptable, too, as per George's comment.

    $ useradd -m -s /bin/bash -p \$6\$5AfGzrQ9u\$r6Q7Vt6h8f2rr4TuW4ZA22m6/eoQh9ciwUuMDtVBX31tR3Tb0o9EB1eBdZ2L9mvT.pX3dIEfxipMoQ0LtTR3V1 newuser
4

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like