如何在bash中向提示输入密码的命令提供密码?

68

我正在编写一个UNIX shell函数,它将执行一个命令,该命令会提示用户输入密码。我想将密码硬编码到脚本中并提供给该命令。我尝试像这样将密码通过管道传递给命令:

function() {
    echo "password" | command
}

某些命令可能无法正常工作,因为在提示输入密码之前,该命令可能会刷新输入缓冲区。

我还尝试过将标准输入重定向到一个包含密码的文件中,但这也不起作用:

function() {
    echo "password" > pass.tmp
    command < pass.tmp
    rm pass.tmp
}

我知道有些命令允许将密码作为参数提供,但我更愿意通过标准输入来输入密码。

我正在寻找一种快速而简单的方法,在bash中将密码传递给命令。


3
你看过autoexpect了吗?它再也没有比那更简单的了。你只需传递命令,它就会记录你所做的一切并为你创建expect文件。 - SiegeX
8个回答

50

如何使用autoexpect将密码传递给命令:

这些步骤以Ubuntu 12.10桌面版为例进行说明。您的发行版的确切命令可能略有不同。

这很危险,因为您可能会将使用的任何密码暴露给可以读取autoexpect脚本文件的任何人。

请勿通过此方式通过expect来传递您的root密码或超级用户密码。Rootkits将在瞬间找到它,并控制您的设备。

EXPECT生成一个进程,读取输入的文本,然后发送在脚本文件中预定义的文本。

  1. 确保您已安装expectautoexpect

sudo apt-get install expect
sudo apt-get install expect-dev
  • 了解一下:

    man expect
    man autoexpect
    
  • 进入你的主目录:

    cd /home/el
    
  • 用户el无法将文件的所有权赋予root用户,必须输入密码:

  • touch testfile.txt
    sudo chown root:root testfile.txt 
       [enter password to authorize the changing of the owner]
    
  • 这是我们想要自动化的密码输入。重新启动终端以确保sudo再次要求输入密码。再次进入/home/el并执行以下操作:

  • touch myfile.txt
    
    autoexpect -f my_test_expect.exp sudo chown root:root myfile.txt
    
        [enter password which authorizes the chown to root]
    
    autoexpect done, file is my_test_expect.exp
    
  • 您已创建my_test_expect.exp文件。 您的超级密码以明文形式存储在此文件中。 这应该让您非常不舒服。 通过尽可能限制权限和所有权来缓解一些不适:

  • sudo chown el my_test_expect.exp     //make el the owner.
    sudo chmod 700 my_test_expect.exp    //make file only readable by el.
    
  • my_test_expect.exp文件底部,您会看到这些类型的命令:

  • set timeout -1
    spawn sudo chown root:root myfile.txt
    match_max 100000
    expect -exact "\[sudo\] password for el: "
    send -- "YourPasswordStoredInPlaintext\r"
    expect eof
    
  • 您需要验证上述expect命令是否适当。如果autoexpect脚本过于敏感或不够敏感,则会挂起。在这种情况下,这是可以接受的,因为expect正在等待始终到达的文本。

  • 以用户el身份运行expect脚本:

  • expect my_test_expect.exp 
    spawn sudo chown root:root myfile.txt
    [sudo] password for el: 
    
    我的测试脚本 my_test_expect.exp 中的密码被用户 el 通过管道传递到 chown 到 root。要查看密码是否被接受,请查看 myfile.txt:
    ls -l
    -rw-r--r--  1 root root          0 Dec  2 14:48 myfile.txt
    

    它能够成功是因为它是root,而el从未输入过密码。 如果您使用此脚本公开了您的root、sudo或超级用户密码,则获取您的系统root权限将变得容易。 这就是一个安全系统允许任何人不加问询地进入的惩罚。


    1
    这篇帖子不应该得到这么多赞。密码是有原因的,而这基本上违背了这个目的。 - Eric Leschinski
    3
    屏幕抓取程序和机器人肉质手指戳着MacBook触摸板以验证我们不是机器人;尽管如此,在Bash中传递明文密码是最糟糕的代码气味,如果有人发明了一台时光机并在我2013年写这篇文章时敲打我一下就好了。 - Eric Leschinski

    32

    看一下 autoexpect(不错的教程在 这里)。它是一种快速而简单的方法,可以避免使用诡计手段。


    1
    太棒了 - 既然我的真正意图是能够快速而简单地完成某些事情,这正是我所需要的! - Nate W.
    节省了我将相同的密码三次输入到实现不佳的 VPN 中的时间。(我还创建了一个只需运行expect vpn.sh的脚本。) - Chazt3n
    3
    在这里包含至少一个快速片段会很好。链接六年后并不总是有效的。这个链接目前还有效,但是 :) - Unsigned
    @Unsigned 更新了链接,以确保其长期存在。虽然不完全符合您的要求,但 Eric 的答案可以帮助您到达目的地。 - SiegeX
    暗示答案并不是回答,而是一种评论。 - goulashsoup

    14
    你可以使用-S标志从标准输入读取内容。以下是一个示例:
    function shutd()
    {
      echo "mySuperSecurePassword" | sudo -S shutdown -h now
    }    
    

    非常感谢。这是一个完美的快速简单实现,非常有效。 - Blake Neal
    如果我有一个命令 run this_command,它会提示输入密码,你会如何修改这个函数? - MAC
    2
    @AwaisKaleem 这个答案应该澄清,它只适用于像 shutdown 这样会导致系统明确提示输入 sudo 密码的命令。这预先避免了调用 shutdown 时需要请求密码的需求,通过使用 sudo 选项 -S 先获取超级用户权限。对于那些自己提示输入密码的命令,它是不起作用的。 - nealmcb
    这很棒!但我不确定为什么我仍然看到“密码:”提示(即使它已经成功跳过)。 - Ricky Levi

    6

    使用read命令

    这是一个例子,使用read命令获取密码并将其存储在变量pass中。然后,7z使用该密码创建加密归档:

    read -s -p "Enter password: " pass && 7z a archive.zip a_file -p"$pass"; unset pass
    

    但请注意,密码可能会轻易被嗅探


    这种方法只适用于像7z这样允许命令行输入密码的命令,而且问题明确要求避免使用这种方法,因为它可能会在shell历史记录中遗留密码并暴露给ps,所以比其他答案更糟糕。 - nealmcb
    如果你想避免密码泄露,请尝试以下命令:read -s -p "输入密码:" pass && ( echo "$pass" | nohup my-command-that-reads-the-password & ) 然后,如果需要的话,你可以关闭窗口。你也可以在read之前添加一个空格字符,以避免该命令出现在历史记录中。 - Goblinhack

    6

    安全命令不允许这样做,这是正确的,我很抱歉——这是一个可以通过的安全漏洞。

    如果您的命令不允许使用输入重定向、命令行参数或配置文件,则必须采取严格的技巧。

    一些应用程序实际上会打开/dev/tty以确保您很难击败安全性。您可以通过暂时接管/dev/tty(例如创建自己的管道)来绕过它们,但这需要严格的特权,甚至也可能会被攻破。


    1
    你说得对,我明白这为什么是一个安全漏洞,但我已经在一个安全的环境中,所以我的主要关注点是快速而不必诉诸于严重的欺骗手段。感谢您的回复! - Nate W.

    2

    通常会提示输入密码的程序会将终端tty设置为“raw”模式,并直接从终端读取输入。如果您在pty中生成子进程,则可以使其正常工作。这就是Expect所做的...


    4
    请给出一个最简单的例子吗? - dibyendu

    2

    只需简单使用:

    echo "password" | sudo -S mount -t vfat /dev/sda1 /media/usb/;
    if [ $? -eq 0 ]; then
        echo -e '[ ok ] Usb key mounted'
    else
        echo -e '[warn] The USB key is not mounted'
    fi
    

    这段代码对我有用,它位于 /etc/init.d/myscriptbash.sh 中。

    -1

    1
    我认为OP不仅仅是在询问passwd - Cascabel

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接