I am writing an expect script to automate diagnostic SSH sessions against a certain type of IoT devices. The script is run from a jump host, where the user running the script needs elevation to access the keyfile used for SSH authentication.
The authentication works and I reach the IoT device's shell prompt, but as I send a command to the prompt (ls -l
in the script below) the output freezes and nothing more happens.
Expect script rundiag.expect
:
#!/usr/bin/expect
set timeout 30
set ip [lindex $argv 0]
set port [lindex $argv 1]
set passphrase [lindex $argv 2]
set ssh_key_file [lindex $argv 3]
spawn /usr/bin/sudo -u sftp /usr/bin/ssh -ldiag_user -i $ssh_key_file $ip -p $port -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no"
expect "passphrase for"
send "$passphrase\r"
expect "DEBUG> "
send "ls -l\r"
expect "DEBUG> "
Output when running script:
$ expect rundiag.expect 10.10.10.123 22 somePassword /opt/the_keyfile
spawn /usr/bin/sudo -u sftp /usr/bin/ssh -ldiag_user -i /opt/the_keyfile 10.10.10.123 -p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
Warning: Permanently added '10.10.10.123:22' (RSA) to the list of known hosts.
Enter passphrase for key '/opt/the_keyfile':
******
Welcome to diagnostics shell
DEBUG> l
The l
echoed at the end is the first character of the ls -l
command, but then the output just stops until the script times out.
I have tried some naive approaches like sending via send_tty or ending the command with \n
instead of \r
, but to no avail.
What should I change to be able to run commands after reaching the shell prompt?
It turned out that the SSH implementation on these IoT devices is quite severely flawed, as it in turn wraps an internal Telnet server for legacy reasons.
Adding a 0.5 second sleep after connecting (while the device connects to itself on another port via Telnet) and a 0.1 second sleep between entering a command and sending \r
did the trick.