67

I'm writing a UNIX shell function that is going to execute a command that will prompt the user for a password. I want to hard-code the password into the script and provide it to the command. I've tried piping the password into the command like this:

function() {
    echo "password" | command
}

This may not work for some commands as the command may flush the input buffer before prompting for the password.

I've also tried redirecting standard input to a file containing the password like this, but that doesn't work either:

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

I know that some commands allow for the password to be provided as an argument, but I'd rather go through standard input.

I'm looking for a quick and dirty way of piping a password into a command in bash.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Nate W.
  • 9,141
  • 6
  • 43
  • 65
  • 3
    Have you looked at `autoexpect` ? It doesn't get much easier than that. You just just pass it the command and it will record everything you do and create the expect file for you. – SiegeX Feb 01 '11 at 00:37

8 Answers8

50

How to use autoexpect to pipe a password into a command:

These steps are illustrated with an Ubuntu 12.10 desktop. The exact commands for your distribution may be slightly different.

This is dangerous because you risk exposing whatever password you use to anyone who can read the autoexpect script file.

DO NOT expose your root password or power user passwords by piping them through expect like this. Root kits WILL find this in an instant and your box is owned.

EXPECT spawns a process, reads text that comes in then sends text predefined in the script file.

  1. Make sure you have expect and autoexpect installed:

    sudo apt-get install expect
    sudo apt-get install expect-dev
    
  2. Read up on it:

    man expect
    man autoexpect
    
  3. Go to your home directory:

    cd /home/el
    
  4. User el cannot chown a file to root and must enter a password:

    touch testfile.txt
    sudo chown root:root testfile.txt 
       [enter password to authorize the changing of the owner]
    
  5. This is the password entry we want to automate. Restart the terminal to ensure that sudo asks us for the password again. Go to /home/el again and do this:

    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
    
  6. You have created my_test_expect.exp file. Your super secret password is stored plaintext in this file. This should make you VERY uncomfortable. Mitigate some discomfort by restricting permissions and ownership as much as possible:

    sudo chown el my_test_expect.exp     //make el the owner.
    sudo chmod 700 my_test_expect.exp    //make file only readable by el.
    
  7. You see these sorts of commands at the bottom of 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
    
  8. You will need to verify that the above expect commands are appropriate. If the autoexpect script is being overly sensitive or not sensitive enough then it will hang. In this case it's acceptable because the expect is waiting for text that will always arrive.

  9. Run the expect script as user el:

    expect my_test_expect.exp 
    spawn sudo chown root:root myfile.txt
    [sudo] password for el: 
    
  10. The password contained in my_test_expect.exp was piped into a chown to root by user el. To see if the password was accepted, look at myfile.txt:

    ls -l
    -rw-r--r--  1 root root          0 Dec  2 14:48 myfile.txt
    

It worked because it is root, and el never entered a password. If you expose your root, sudo, or power user password with this script, then acquiring root on your box will be easy. Such is the penalty for a security system that lets everybody in no questions asked.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • 1
    This post should not be as upvoted as it is. Passwords are made for a reason, and this mostly defeats that purpose. – Eric Leschinski Oct 27 '16 at 20:59
  • 3
    Screen-scrapers and Robot Fleshy Fingers poking macbook trackpads to certify we aren't a robot; notwithstanding, passing around passwords cleartext in bash is the worst code-smell of all, Someone invent a time-machine and hit me over the head when I wrote this in 2013. – Eric Leschinski May 27 '21 at 18:18
32

Take a look at autoexpect (decent tutorial HERE). It's about as quick-and-dirty as you can get without resorting to trickery.

SiegeX
  • 135,741
  • 24
  • 144
  • 154
  • 1
    Wonderful - seeing as how my real intent is to be able to do something quick-n-dirty, this is just what I need! – Nate W. Feb 01 '11 at 22:07
  • Saved me typing the same password three times into my sadly implemented VPN. (I also created a script that just runs ```expect vpn.sh```) – Chazt3n May 25 '15 at 14:49
  • 3
    It would be great to have at least a quick snippet included in the answer here. Links don't *always* work six years later. This one does, but :) – Unsigned Jun 26 '17 at 18:11
  • @Unsigned updated the link to ensure this will stick around for a long time. Not exactly what you're looking for but Eric's answer gets you there. – SiegeX Jul 10 '17 at 07:26
  • Hinting to an answer is NOT an answer but a comment. – goulashsoup Jun 21 '23 at 11:24
14

You can use the -S flag to read from std input. Find below an example:

function shutd()
{
  echo "mySuperSecurePassword" | sudo -S shutdown -h now
}    
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Roozbeh
  • 149
  • 1
  • 4
  • Thank you kindly. This works perfectly as a quick-and-dirty, vanilla implementation. – Blake Neal Sep 11 '17 at 19:55
  • If I have a command `run this_command` which prompts for password, how would you change this function? – MAC Apr 07 '20 at 08:47
  • 2
    @AwaisKaleem This answer should clarify that it only works for commands like `shutdown` which cause the system to specificially prompt for the `sudo` password. This preempts the need for the invocation of `shutdown` to ask for a password, by first getting superuser permisions via the `sudo` option `-S`. It won't work for commands which themselves prompt for passwords. – nealmcb Jul 03 '20 at 20:31
  • this is great ! but not sure why I still see the `Password:` prompt ( even though it was skipped successfully ) – Ricky Levi Aug 24 '22 at 09:30
6

Secure commands will not allow this, and rightly so, I'm afraid - it's a security hole you could drive a truck through.

If your command does not allow it using input redirection, or a command-line parameter, or a configuration file, then you're going to have to resort to serious trickery.

Some applications will actually open up /dev/tty to ensure you will have a hard time defeating security. You can get around them by temporarily taking over /dev/tty (creating your own as a pipe, for example) but this requires serious privileges and even it can be defeated.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    You're right, I understand why this is a security hole, but I'm already in a secure environment so my primary concern is something quick-n-dirty without having to resort to serious trickery. Thanks for the response! – Nate W. Feb 01 '11 at 22:09
6

with read

Here's an example that uses read to get the password and store it in the variable pass. Then, 7z uses the password to create an encrypted archive:

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

But be aware that the password can easily be sniffed.

Chris
  • 5,788
  • 4
  • 29
  • 40
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
  • This approach only works for commands like `7z` which allow command-line entry of the password, and the question specifically asked to avoid that approach, since it probably leaves the password sitting around in the shell history and exposed to `ps`, so it is far worse than the other answers here. – nealmcb Jul 03 '20 at 20:39
  • If you want to avoid the password leakage, try: `read -s -p "Enter password: " pass && ( echo "$pass" | nohup my-command-that-reads-the-password & )` You should then be able to close the window if you want - and you can also add a char before read to avoid even the command appearing in the history. – Goblinhack May 30 '23 at 08:56
2

Simply use :

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

This code is working for me, and its in /etc/init.d/myscriptbash.sh

Alex Bins
  • 21
  • 2
2

Programs that prompt for passwords usually set the tty into "raw" mode, and read input directly from the tty. If you spawn the subprocess in a pty you can make that work. That is what Expect does...

Keith
  • 42,110
  • 11
  • 57
  • 76
-1

That's a really insecure idea, but: Using the passwd command from within a shell script

Community
  • 1
  • 1
Ratinho
  • 298
  • 1
  • 6