bashprocesslist

how dangerous is to echo passwords via pipe to passwd


I've seen in more than one discussion that using echo to pipe to passwd is dangerous because one can get arguments provided to echo from process list.

I'm currently working on a tool, that changes passwords remotely via ssh. I do use echo method because I do not have root access to use usermod or chpasswd.

cmd:

echo -e 'old\nnew\nnew' | passwd

To check how easy it is - I tried. But could not get them.

this was my method:

#!/bin/bash
filename=$1

while true
do
    echo "$(pgrep -af passwd)" >> "$filename"
    sleep 0.1
done

I few times changed password via echo but could not seen anything. I think that sleep 0.1 may be a problem.

How easy it is to get it from process list and therefore how insecure it is to use it this way.


Solution

  • It depends on whether the shell you're using has echo as a builtin, or uses an external binary (/bin/echo). If it's an external binary, it'll be run as a subprocess with the password plainly visible in its argument list (via ps, pgrep, etc). If it's a builtin, an echo command in a pipeline will run as a subprocess, but it'll be a subshell with the same visible argument list as the parent shell (i.e. it's safe).

    So it's probably safe, but there are several complications to worry about. First, if you're running this on a remote computer via ssh, you don't necessarily know what its default shell is. If it's bash, you're ok. If it's dash, I think you have a problem. Second, you don't just have to worry about the remote shell and/or echo command, you have to worry about every step along the path from your local script to that remote echo command. For example, if you use:

    ssh user@computer "echo -e 'old\nnew\nnew' | passwd"
    

    ...then the remote echo is probably safe (depending on the remote shell), but as @thatotherguy pointed out the password will be visible in both the remote shell's (bash -c echo -e 'foo\nbar\nbar' | passwd) and in the local ssh process's argument list.

    There's another complication, BTW: echo isn't consistent about how it handles options (like -e) and escapes in the output string (see this question for an example). You're much better off using printf (e.g. printf '%s\n' "$oldpass" "$newpass" "$newpass"), which is also a builtin in bash. Or, if you're sure you're using bash, you can use here-string (<<<string) instead. It doesn't interpret escapes at all, but you can use bash's $' ' construct to interpret them:

    passwd <<<"$old"$'\n'"$new"$'\n'"$new"
    

    This doesn't involve a subprocess at all (either /bin/echo or a subshell), so no worries about the process table.

    Another possibility to avoid both the problems of uncertain remote shells and the password showing up in ssh's argument list is to pass the passwords via ssh's stdin:

    ssh user@computer passwd <<<"$old"$'\n'"$new"$'\n'"$new"