可以期望脚本从stdin读取数据吗? [英] Can expect scripts read data from stdin?
问题描述
执行expect
脚本时,参数在ps ax
上可见,如果它们很敏感,则可能是安全漏洞.
尝试自动打开iTerm2上的选项卡,运行ssh admin@host
,并在询问Enter passphrase for key '/Users/admin/.ssh/key'
时输入密码(密钥使用该密码加密).
Host host
HostName 1.2.3.4
IdentityFile ~/.ssh/key
我想使用read -sp 'Passphrase: ' passphrase
将密码短语提供给bash,然后将其通过管道传递到expect
(从OPSEC的角度来看这并不完美,但比ps ax
上的密码短语泄漏要好得多).
也许有更好的方法吗?
下面是一些可以工作的代码,但会泄漏ps ax
上的密码短语.已注释掉是我希望的可能性(将密码短语输入expect
).
batch.sh
#!/bin/bash
function new_tab() {
command=${1//\"/\\\"}
osascript \
-e "tell application \"iTerm2\"" \
-e "tell current window" \
-e "create tab with default profile" \
-e "delay 1" \
-e "tell current session" \
-e "write text \"$command\"" \
-e "end tell" \
-e "end tell" \
-e "end tell" > /dev/null
}
hostnames=(
"hostname-1"
"hostname-2"
)
read -sp 'Passphrase: ' passphrase
for hostname in "${hostnames[@]}"; do
# new_tab "echo $passphrase | expect $(pwd)/expect.exp \"$hostname\""
new_tab "expect $(pwd)/expect.exp \"$hostname\" \"$passphrase\""
done
expect.exp
#!/usr/bin/expect
set hostname [lindex $argv 0]
set passphrase [lindex $argv 1]
spawn ssh admin@$hostname
expect "passphrase"
send "$passphrase\r"
interact
是的,expect
可以从stdin
读取,但是有一个警告:从stdin
读取与interact
不兼容.>
请参见 https://stackoverflow.com/a/57847199/4579271
读取单个变量
#!/usr/bin/expect
set passphrase [gets stdin]
读取多个变量
#!/usr/bin/expect
set data [gets stdin]
scan $data "%s %s" hostname passphrase
另一种方法是使用环境变量(如Glenn所建议的),但还有一个警告:环境变量仅可用于定义它们的外壳及其子对象.
因此,在batch.sh
中定义的环境变量在使用osascript
创建的iTerm2选项卡中将不可用.
因此,我唯一安全的选择是完全删除osascript
并使所有代码(batch.sh
和expect.exp
)在同一外壳中执行,并使用环境变量在bash
和
batch.sh
#!/bin/bash
hostnames=(
"hostname-1"
"hostname-2"
)
read -sp 'SSH key passphrase: ' passphrase
echo ""
export PASSPHRASE=$passphrase
for hostname in "${hostnames[@]}"; do
export HOSTNAME=$hostname
expect "$(dirname "$0")/expect.exp"
done
expect.exp
#!/usr/bin/expect
set timeout 10
spawn ssh admin@$env(HOSTNAME)
expect {
default {
puts "\nCould not connect to $env(HOSTNAME)"
exit 1
}
"passphrase" {
send "$env(PASSPHRASE)\r"
}
}
expect {
default {
puts "\nWrong passphrase"
exit 1
}
"admin@$env(HOSTNAME)" {
# Add automation commands here, then exit SSH session to close expect script moving on to the next hostname
send "exit\r"
}
}
interact
When executing expect
scripts, arguments are visible on ps ax
which can be a security vulnerability if they are sensitive.
Trying to automate opening a tab on iTerm2, running ssh admin@host
and entering the passphrase when asked Enter passphrase for key '/Users/admin/.ssh/key'
(the key is encrypted using that passphrase).
Host host
HostName 1.2.3.4
IdentityFile ~/.ssh/key
I would like to supply the passphrase to bash using read -sp 'Passphrase: ' passphrase
and then pipe it to expect
(which isn’t perfect at all from an OPSEC perspective but much better than having the passphrase leaked on ps ax
).
Perhaps there is a better way?
Bellow is some code that works but leaks the passphrase on ps ax
. Commented out is what I wish was possible (piping the passphrase to expect
).
batch.sh
#!/bin/bash
function new_tab() {
command=${1//\"/\\\"}
osascript \
-e "tell application \"iTerm2\"" \
-e "tell current window" \
-e "create tab with default profile" \
-e "delay 1" \
-e "tell current session" \
-e "write text \"$command\"" \
-e "end tell" \
-e "end tell" \
-e "end tell" > /dev/null
}
hostnames=(
"hostname-1"
"hostname-2"
)
read -sp 'Passphrase: ' passphrase
for hostname in "${hostnames[@]}"; do
# new_tab "echo $passphrase | expect $(pwd)/expect.exp \"$hostname\""
new_tab "expect $(pwd)/expect.exp \"$hostname\" \"$passphrase\""
done
expect.exp
#!/usr/bin/expect
set hostname [lindex $argv 0]
set passphrase [lindex $argv 1]
spawn ssh admin@$hostname
expect "passphrase"
send "$passphrase\r"
interact
Yes, expect
can read from stdin
but there is a caveat: reading from stdin
isn’t compatible with interact
.
See https://stackoverflow.com/a/57847199/4579271
Reading a single variable
#!/usr/bin/expect
set passphrase [gets stdin]
Reading multiple variables
#!/usr/bin/expect
set data [gets stdin]
scan $data "%s %s" hostname passphrase
Another approach is to use environment variables (as suggested by Glenn) but there is another caveat: environment variables are only available to the shell in which they are defined and its children.
Environment variables defined in batch.sh
would therefore not be available in the iTerm2 tabs created using osascript
.
So the only secure option I have is to drop osascript
altogether and have all the code (batch.sh
and expect.exp
) execute in the same shell and use environment variables to pass variables between bash
and expect
.
batch.sh
#!/bin/bash
hostnames=(
"hostname-1"
"hostname-2"
)
read -sp 'SSH key passphrase: ' passphrase
echo ""
export PASSPHRASE=$passphrase
for hostname in "${hostnames[@]}"; do
export HOSTNAME=$hostname
expect "$(dirname "$0")/expect.exp"
done
expect.exp
#!/usr/bin/expect
set timeout 10
spawn ssh admin@$env(HOSTNAME)
expect {
default {
puts "\nCould not connect to $env(HOSTNAME)"
exit 1
}
"passphrase" {
send "$env(PASSPHRASE)\r"
}
}
expect {
default {
puts "\nWrong passphrase"
exit 1
}
"admin@$env(HOSTNAME)" {
# Add automation commands here, then exit SSH session to close expect script moving on to the next hostname
send "exit\r"
}
}
interact
这篇关于可以期望脚本从stdin读取数据吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!