Verwenden Sie Expect in Bash Script, um das Kennwort für den SSH-Befehl bereitzustellen

131

Für diejenigen, die antworten möchten, dass ich SSH-Schlüssel verwenden soll, enthalten Sie sich bitte

Ich versuche, Expect in einem Bash-Skript zu verwenden, um das SSH-Passwort bereitzustellen. Wenn Sie das Passwort angeben, funktioniert es, aber ich lande nicht wie gewünscht in der SSH-Sitzung. Es geht zurück zur Bash.

Mein Skript:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com'
expect "password"
send "$PWD\n" 
EOD
echo "you're out"

Die Ausgabe meines Skripts:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
usr@$myhost.example.com's password: you're out

Ich möchte meine SSH-Sitzung nur dann haben, wenn ich sie beende, um zu meinem Bash-Skript zurückzukehren. Der Grund, warum ich bash vor der Erwartung verwende, ist, dass ich ein Menü verwendet habe, mit dem ich auswählen kann, mit welchem ​​Gerät ich eine Verbindung herstellen möchte.

Vielen Dank

Max
quelle
49
siehe erste Zeile: Für diejenigen, die antworten möchten, dass ich SSH-Schlüssel verwenden soll, enthalten Sie sich bitte
Max
54
Ich würde Ihre erste Zeile bearbeiten, um ein wenig freundlicher zu sein. Sie könnten etwas in Betracht ziehen wie "Aufgrund von Einschränkungen kann ich SSH-Schlüssel einfach nicht verwenden, ich muss einen Weg finden, um es mit Expect zum Laufen zu bringen". Sie sollten erwarten, dass die Leute von Natur aus neugierig sind, warum Sie keine Schlüssel verwenden, und nur versuchen, hilfreich zu sein :) @Ignacio hat nicht vorgeschlagen , dass Sie sie verwenden, er hat dies lediglich als Einschränkung und nicht als Versehen bestätigt.
Tim Post
Ich würde versuchen, in diesem Fall Kermit zu verwenden. Es hat eine sehr robuste Skriptsprache columbia.edu/kermit/skermit.html#scripts
f3xy

Antworten:

86

Das Mischen von Bash und Expect ist kein guter Weg, um den gewünschten Effekt zu erzielen. Ich würde versuchen, nur Expect zu verwenden:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
#use correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact

Beispiellösung für Bash könnte sein:

#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com; interact }'

Dies wartet auf die Eingabe und kehrt dann (für einen Moment) zur interaktiven Sitzung zurück.

Piotr Król
quelle
1
es funktioniert super, danke. Was muss ich tun, wenn ich nach der Anmeldung über SSH einen Befehl eingeben möchte?
Max
Dieses Skript sollte eine inaktive Shell mit dem angemeldeten Benutzer zurückgeben. Ich verstehe die Frage nicht. Wenn Sie unbedingt dasselbe Skript in Bash verwenden möchten, schauen Sie sich den bearbeiteten Eintrag an.
Piotr Król
Auf die gleiche Weise, wie ich das Kennwort sende, wenn ich dazu aufgefordert werde, möchte ich nach dem Anmelden Systembefehle senden.
Max
Beispielcode wurde hinzugefügt, um oben zu posten. Dies funktioniert natürlich so lange, bis my_commandX die zurückgegebene Eingabeaufforderung nicht mehr ändert. In diesem Fall sollte die Eingabeaufforderungsvariable geändert werden.
Piotr Król
@pietrushnic Kannst du ein bisschen erklären, warum "Interact -o -nobuffer -re $ prompt return" anstelle von "require $ prompt" verwendet wird? Letzteres scheint häufiger verwendet zu werden ..
Richard
53

Am einfachsten ist es, sshpass zu verwenden . Dies ist in Ubuntu / Debian-Repos verfügbar und Sie müssen sich nicht mit der Integration von Expect in Bash befassen.

Ein Beispiel:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh user@192.168.1.200 ls -l /tmp

Der obige Befehl kann einfach in ein Bash-Skript integriert werden.

Hinweis: Bitte lesen Sie den Abschnitt man sshpassSicherheitsüberlegungen in, um die Auswirkungen auf die Sicherheit vollständig zu verstehen.

dotnix
quelle
Ich weiß nicht, ob es eine gute Lösung ist, aber es vereinfacht sicherlich sehr. Danke
erikbwork
9
Aus Sicherheitsgründen sehr gefährlich - Befehlszeilenargumente können von jedem anderen Prozess im System gelesen werden. Es ist möglich, sie zu überschreiben, und das sshpasstut es hoffentlich , aber selbst dann gibt es eine Zeitspanne, in der es noch startet, bevor es dies tun kann, wenn das Passwort für jeden Prozess verfügbar ist.
Charles Duffy
1
@ CharlesDuffy Natürlich bist du richtig. sshpasswird in einem Szenario verwendet, in dem Sie einfache Testskripte haben, die in einer lokalen Netzwerkumgebung ausgeführt werden, in der Sicherheit nicht das Hauptanliegen ist. Tatsächlich gibt es einen Abschnitt, in man sshpassdem ein ganzer Abschnitt zu Sicherheitsaspekten erläutert wird. Fügte dies hinzu, um zu antworten: Danke.
Dotnix
@ erikb85 Normalerweise erledigt ein Paket alle schmutzigen Dinge für Sie, aber in allen Fällen sind diese Skripte nur für diese Verwendung erstellt und dann BESSER, als Ihre eigenen Dinge hinzuzufügen. In diesem Kommentar geht es darum, das Rad nicht neu zu erfinden. Beschäftige dich nur mit harten Sachen, wenn sich noch niemand damit befasst hat. sshpass es ist eine gute Funktion.
m3nda
2
Der Vollständigkeit halber erwähne ich, dass "man sshpass" dem potenziellen Benutzer geeignete Sicherheitswarnungen liefert, darauf hinweist, dass "-p" die am wenigsten sichere Art der Verwendung ist, und die Option "-e" bietet, um das Kennwort über die Umgebungsvariable zu übernehmen , was es zumindest von der Kommandozeile fernhält.
Ron Burk
22

Fügen Sie den Befehl "Interact" Expect kurz vor Ihrem EOD hinzu:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
expect "password"
send "$PWD\n" 
interact
EOD
echo "you're out"

Auf diese Weise können Sie mit dem Remotecomputer interagieren, bis Sie sich abmelden. Dann bist du wieder in Bash.

dr-jan
quelle
Es geht rein und geht sofort wieder raus. "du bist raus" wird gedruckt.
Emmanuel
8
Ich habe "Interact" und "EOD" durch "Expect Eof" ersetzt und es hat bei mir funktioniert. Dies ist auf einem Mac.
Emmanuel
2
Keine der Antworten auf dieser Seite funktionierte für mich, aber @ Emmanuels Vorschlag zur Verwendung expect eoflöste das Problem.
Moertel
Entfernen Sie die 'von usr@$myhost.example.com'und es sollte funktionieren. Und vielleicht müssen Sie ersetzen \nmit \r, aber YMMV
Tino
19

Nachdem ich monatelang nach einer Antwort auf die Frage gesucht habe, finde ich endlich eine wirklich beste Lösung: ein einfaches Skript zu schreiben.

#!/usr/bin/expect

set timeout 20

set cmd [lrange $argv 1 end]
set password [lindex $argv 0]

eval spawn $cmd
expect "Password:"
send "$password\r";
interact

Setzen Sie es auf /usr/bin/exp, dann können Sie verwenden:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

Getan!

verdammt_c
quelle
expect "assword:"hast du gemeint expect "password:"?
Benutzer
1
@user "assword"wird sowohl mit Passwordals auch übereinstimmen password.
Ferdinand.kraft
8

Stellen Sie auch sicher, zu verwenden

send -- "$PWD\r" 

Stattdessen schlagen Kennwörter, die mit einem Bindestrich (-) beginnen, ansonsten fehl.

Das Obige interpretiert eine Zeichenfolge, die mit einem Bindestrich beginnt, nicht als Option für den Sendebefehl.

Timmah
quelle
8

Ein einfaches Erwartungsskript

Remotelogin.exp

    #!/usr/bin/expect
    set user [lindex $argv 1]
    set ip [lindex $argv 0]
    set password [lindex $argv 2]
    spawn ssh $user@$ip
    expect "password"
    send "$password\r"
    interact

Beispiel:

    ./Remotelogin.exp <ip> <user name> <password>
Vijay SB
quelle
7

Verwenden Sie das fd0sshHilfsprogramm (von hxtools, nicht von pmt). Es funktioniert, ohne dass Sie eine bestimmte Eingabeaufforderung vom ssh-Programm erwarten müssen.

user562374
quelle
Das ist toll! Es ist ein bisschen schwierig, es zum Laufen zu bringen (zumindest auf dem Ubuntu-Server), aber es funktioniert reibungslos! Die Konfiguration, die wir gemacht haben: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port [email protected] & DANKE!
JP Illanes
1
Viel sicherer als das Passwort in der Kommandozeile zu übergeben sshpass.
Charles Duffy
5

Eine andere Möglichkeit, die ich nützlich fand, um ein kleines Expect-Skript aus einem Bash-Skript zu verwenden, ist die folgende.

...
bash-script start
bash-commands
...
expect - <<EOF 
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
more bash commands
...

Das funktioniert weil ...If the string "-" is supplied as a filename, standard input is read instead...

Jimbo
quelle
Sie benötigen das -hier nicht, da es standardmäßig expectliest, stdinwenn Sie es ohne Argument aufrufen. Es ist jedoch nützlich, wenn Sie es interaktiv ohne Eingabeaufforderung ( expectvs. expect -) ausführen möchten oder wenn Sie etwas tun, expect -f "$@"bei dem das erste Argument eine Datei sein soll, auch wenn es wie eine Option aussieht (beginnt mit -). In diesem Fall liest if $1(die angegebene Datei) -aus stdin.
Tino
1

sshpassist fehlerhaft, wenn Sie versuchen, es innerhalb des Erstellungsziels von Sublime Text in einem Makefile zu verwenden. Stattdessen sshpasskönnen Sie verwenden passh: https://github.com/clarkwang/passh

Mit sshpassdir würde tun:

sshpass -p pa$$word ssh user@host

Mit passhdir würde tun:

passh -p pa$$word ssh user@host

Hinweis: Vergessen Sie nicht -o StrictHostKeyChecking=no, die Verbindung zu verwenden , da sie sonst bei der ersten Verwendung hängen bleibt. Beispielsweise:

passh -p pa$$word ssh -o StrictHostKeyChecking=no user@host

Verweise:

  1. Der Sendebefehl für das Passwort funktioniert nicht mit dem Expect-Skript in der SSH-Verbindung
  2. /ubuntu/87449/how-to-disable-strict-host-key-checking-in-ssh
  3. https://linuxcommando.blogspot.com/2008/10/how-to-disable-ssh-host-key-checking.html
  4. /server/330503/scp-without-known-hosts-check
  5. https://debian-administration.org/article/587/pam_mount_and_sshfs_with_password_authentication
Benutzer
quelle