通过管道将密码回显到 passwd 有多危险
how dangerous is to echo passwords via pipe to passwd
我在不止一次讨论中看到使用 echo 将管道传递给 passwd 是危险的,因为可以从进程列表中获取提供给 echo 的参数。
我目前正在开发一种工具,可以通过 ssh 远程更改密码。我确实使用 echo 方法,因为我没有使用 usermod 或 chpasswd 的 root 访问权限。
命令:
echo -e 'old\nnew\nnew' | passwd
为了检查它有多容易 - 我试过了。但无法得到它们。
这是我的方法:
#!/bin/bash
filename=
while true
do
echo "$(pgrep -af passwd)" >> "$filename"
sleep 0.1
done
我几次通过回显更改密码但什么也看不到。我认为 sleep 0.1 可能是个问题。
从进程列表中获取它是多么容易,因此以这种方式使用它是多么不安全。
这取决于您使用的 shell 是内置 echo
还是使用外部二进制文件 (/bin/echo)。如果它是一个外部二进制文件,它将是 运行 作为一个子进程,其密码在其参数列表中清晰可见(通过 ps
、pgrep
等)。如果它是内置的,管道中的 echo
命令将 运行 作为子进程,但它将是一个子 shell 与父 [=55= 具有相同的可见参数列表](即它是安全的)。
所以它可能 是安全的,但是有一些并发症需要担心。首先,如果您通过 ssh
在远程计算机上 运行 设置它,您不一定知道它的默认值 shell 是什么。如果是 bash,你没问题。如果是破折号,我认为你有问题。其次,您不必担心远程 shell and/or echo
命令,您还需要担心从本地脚本到远程 [=13] 的路径中的每一步=] 命令。例如,如果您使用:
ssh user@computer "echo -e 'old\nnew\nnew' | passwd"
...那么远程 echo
可能是安全的(取决于远程 shell),但正如@thatotherguy 指出的那样,密码在远程 shell 中都是可见的] 的 (bash -c echo -e 'foo\nbar\nbar' | passwd
) 和 在本地 ssh
进程的参数列表中。
还有一个问题,顺便说一句:echo
在处理选项(如 -e
)和在输出字符串中转义的方式上并不一致(参见 的示例) .你最好使用 printf
(例如 printf '%s\n' "$oldpass" "$newpass" "$newpass"
),它也是 bash 中的内置函数。或者,如果您确定使用的是 bash,则可以改用 here-string (<<<string
)。它根本不解释转义符,但您可以使用 bash 的 $' '
构造来解释它们:
passwd <<<"$old"$'\n'"$new"$'\n'"$new"
这根本不涉及子进程(/bin/echo
或子进程shell),所以不用担心进程 table。
另一种避免不确定的远程 shells 和密码出现在 ssh
的参数列表中的问题的可能性是通过 ssh
的标准输入传递密码:
ssh user@computer passwd <<<"$old"$'\n'"$new"$'\n'"$new"
如果您要通过 ssh
调用 echo|passwd
命令,例如:
client$ ssh example.com "echo -e 'foo\nbar\nbar' | passwd"
那么您需要查看的过程不是 passwd
,而是 sshd
在远程端调用的用户登录 shell:
server$ until pgrep -af bash | grep passwd; do true; done
8387 bash -c echo -e 'foo\nbar\nbar' | passwd
我在不止一次讨论中看到使用 echo 将管道传递给 passwd 是危险的,因为可以从进程列表中获取提供给 echo 的参数。
我目前正在开发一种工具,可以通过 ssh 远程更改密码。我确实使用 echo 方法,因为我没有使用 usermod 或 chpasswd 的 root 访问权限。
命令:
echo -e 'old\nnew\nnew' | passwd
为了检查它有多容易 - 我试过了。但无法得到它们。
这是我的方法:
#!/bin/bash
filename=
while true
do
echo "$(pgrep -af passwd)" >> "$filename"
sleep 0.1
done
我几次通过回显更改密码但什么也看不到。我认为 sleep 0.1 可能是个问题。
从进程列表中获取它是多么容易,因此以这种方式使用它是多么不安全。
这取决于您使用的 shell 是内置 echo
还是使用外部二进制文件 (/bin/echo)。如果它是一个外部二进制文件,它将是 运行 作为一个子进程,其密码在其参数列表中清晰可见(通过 ps
、pgrep
等)。如果它是内置的,管道中的 echo
命令将 运行 作为子进程,但它将是一个子 shell 与父 [=55= 具有相同的可见参数列表](即它是安全的)。
所以它可能 是安全的,但是有一些并发症需要担心。首先,如果您通过 ssh
在远程计算机上 运行 设置它,您不一定知道它的默认值 shell 是什么。如果是 bash,你没问题。如果是破折号,我认为你有问题。其次,您不必担心远程 shell and/or echo
命令,您还需要担心从本地脚本到远程 [=13] 的路径中的每一步=] 命令。例如,如果您使用:
ssh user@computer "echo -e 'old\nnew\nnew' | passwd"
...那么远程 echo
可能是安全的(取决于远程 shell),但正如@thatotherguy 指出的那样,密码在远程 shell 中都是可见的] 的 (bash -c echo -e 'foo\nbar\nbar' | passwd
) 和 在本地 ssh
进程的参数列表中。
还有一个问题,顺便说一句:echo
在处理选项(如 -e
)和在输出字符串中转义的方式上并不一致(参见 printf
(例如 printf '%s\n' "$oldpass" "$newpass" "$newpass"
),它也是 bash 中的内置函数。或者,如果您确定使用的是 bash,则可以改用 here-string (<<<string
)。它根本不解释转义符,但您可以使用 bash 的 $' '
构造来解释它们:
passwd <<<"$old"$'\n'"$new"$'\n'"$new"
这根本不涉及子进程(/bin/echo
或子进程shell),所以不用担心进程 table。
另一种避免不确定的远程 shells 和密码出现在 ssh
的参数列表中的问题的可能性是通过 ssh
的标准输入传递密码:
ssh user@computer passwd <<<"$old"$'\n'"$new"$'\n'"$new"
如果您要通过 ssh
调用 echo|passwd
命令,例如:
client$ ssh example.com "echo -e 'foo\nbar\nbar' | passwd"
那么您需要查看的过程不是 passwd
,而是 sshd
在远程端调用的用户登录 shell:
server$ until pgrep -af bash | grep passwd; do true; done
8387 bash -c echo -e 'foo\nbar\nbar' | passwd