求助,有什么办法能够控制 cmd/powershell 进行 ssh 自动化登录?

66 天前
 aizya

遇到一个自动化登录的问题,不是简单的 ssh 免密登录哈,要求如下:

环境:Windows10

需求: 输入 ssh 登录系统后,会自动弹出一个 SHA256 的码,需要能够获取到这个码,再调用一个外部的 REST 接口获取动态密码后,点击 YES,输入密码,进入 Linux 系统。

C:\Users\xxx)>ssh root@192.168.xxx.xxx
The authenticity of host '192.168.xxx.xxx (192.168.xxx.xxx:)’can't be established
ED25519 key fingerprint is SHA256:edVhpWttoR1W/30HxIn2BiefgyDj6YZuxxxxr2YNo.
This key is not known by any other names
Are you sure you want to continue connecting(yes/no/[fingerprint])?yes

困难:1. 如何获取 cmd/powershell 中展示内容? 2. 如何自动控制 cmd 输入密码?

希望有大哥能提供一点思路,最好是用 Python 方案。

1963 次点击
所在节点    程序员
25 条回复
tool2dx
66 天前
一般不用管 sha256 ,我用"echo y | ssd ", 可以自动输入 yes
zhlxsh
66 天前
paramiko
Wh0amis
66 天前
import pexpect

# 启动 cmd
child = pexpect.spawn("cmd.exe")

# 等待 cmd 提示符出现
child.expect("C:\\")

# 输入 ssh 命令
child.sendline("ssh user@example.com")

# 等待输入密码的提示
child.expect("password:")

# 输入密码
child.sendline("mypassword")

# 等待登录成功
child.expect("#")

# 获取登录后的输出
print(child.before.decode())
caomingjun
66 天前
获取 fingerprint 有现成的 ssh-keyscan ,不需要强行读 ssh 输出。sshpass 也支持直接通过选项指定密码登陆。

你甚至不需要经过 powershell ,我估计 python 有现成的包可以把上面这些事情都干了。
263
66 天前
import paramiko
import hashlib
import base64
import getpass

def get_host_key_fingerprint(hostname, port=22):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

try:
client.connect(hostname, port=port, username='dummy', password='dummy')
except:
pass

key = client.get_transport().get_remote_server_key()
fingerprint = hashlib.sha256(key.get_fingerprint()).hexdigest()

client.close()
return ':'.join(a+b for a,b in zip(fingerprint[::2], fingerprint[1::2]))

def ssh_login_with_otp(hostname, username, password, otp_func):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 获取 fingerprint
fingerprint = get_host_key_fingerprint(hostname)
print(f"Host key fingerprint: {fingerprint}")

# 验证 fingerprint
if input("Verify fingerprint (y/n): ").lower() != 'y':
print("Fingerprint verification failed")
return

# 获取动态密码
otp = otp_func()

try:
client.connect(hostname, username=username, password=password+otp)
print("Login successful!")

# 执行命令
stdin, stdout, stderr = client.exec_command('ls -l')
print(stdout.read().decode())

except Exception as e:
print(f"Login failed: {str(e)}")

finally:
client.close()

# 模拟获取动态密码的函数
def get_otp():
return input("Enter OTP: ")

# 使用示例
hostname = 'example.com'
username = 'your_username'
password = getpass.getpass("Enter password: ")

ssh_login_with_otp(hostname, username, password, get_otp)


gpt yyds
aizya
66 天前
@Wh0amis 好像不行,我的脚本要在 windows 上运行,pexpect 对 windows 支持好像不是特别好。

https://github.com/pexpect/pexpect/issues/567
virusdefender
66 天前
fingerprint 我记得不是固定的么,先用一个非交互式的程序获取一次,然后生成密码,再用正常的 ssh 登录的库感觉会比较简单。
CEBBCAT
66 天前
这是两个问题,第一个是要你确认对方公钥的,另外一个问题是登录时要求提供动态密码的。
millson
66 天前
yiyiwa
66 天前
import-module posh-ssh

这个模块可以解决。
raviscioniemeche
66 天前
感觉这个不用包都能解决呢,直接拿到 io 对象,输入密码然后输入\r\n 这样不行么
1rv013c6aiWPGt24
66 天前
不太懂,但是我记得可以配置 ssh 免密登录的,就是用 ssh 生成的 key ,之前用 Windowsterminal 登录服务器的时候就这样弄得
aizya
66 天前
@caomingjun emm.. 你看我最新补充的需求,并不只是 SSH 免密。
@263 谢谢回复,这个代码运行起来不太满足我的需求。
zhangeric
66 天前
python 不熟,不过可以开 cmd 或 powershell,截图加 ocr 获取 sha,然后获取 key,然后模拟输入.
.net 下可以用 Process 类将 cmd 或者 powershell 的 StandardInput 和 StandardOutput 重定向进行操作.
cheng6563
66 天前
直接读写 stdout ,stdin 就行了吧
你找下相关库,应该有 API 是启动进程时手动处理输入输出流的
cheng6563
66 天前
Process process = Runtime.getRuntime().exec("cmd /c ...");
InputStream inputStream = process.getInputStream();
OutputStream outputStream = process.getOutputStream();
InputStream errorStream = process.getErrorStream();

java 就是这样,可以获得 3 个流,从 outputStream 可以读到 ssh 打出来的文本,之后把密码模拟按键写到 inputStream 里去。要注意用 sleep 之类的方法控制流程。
263
66 天前
import subprocess
import requests


def get_otp(dynamic_code):
api_url = 'https://api.example.com/get_otp'
response = requests.post(api_url, json={'dynamic_code': dynamic_code})
return response.json()['otp']


ssh_process = subprocess.Popen(
['ssh', 'root@192.168.1.1'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
)

dynamic_code = ''
while True:
output = ssh_process.stdout.readline()
if 'Dynamic code:' in output:
dynamic_code = output.split('Dynamic code:')[1].strip()
break

otp = get_otp(dynamic_code)

ssh_process.stdin.write(f'{otp}\n')
ssh_process.stdin.flush()

while True:
output = ssh_process.stdout.readline()
print(output.strip())
if 'Last login:' in output:
print("登录成功!")
break
elif 'Permission denied' in output:
print("登录失败!")
break

ssh_process.stdin.close()
ssh_process.stdout.close()
ssh_process.stderr.close()


CLAUDE 3.5 SONNET
error451
66 天前
Python 用 subprocess 下的 Popen 可执行 shell 命令, 可以将 stdout, stdin 重定向,利用 subprocess.PIPE ,就可以实现交互式命令执行。
然后用 re 模块, 写正则表达式来读取 stdout 中输出的 SHA256 token
Radiation
66 天前
用 python 的 ssh 库不更好吗,手动实现一个简单的客户端,可操作的范围也大了。
LonnyWong
66 天前
可以自己改一下 tssh 的代码 https://github.com/trzsz/trzsz-ssh/blob/d154d5bba805fa21d36fd0b02a4df6cd4dae374d/tssh/login.go#L593

将 question 传给配置的 OtpCommand1 命令,这个命令对应的程序再自己实现,从参数 question 解释出 SHA256 码,调用 REST 接口获取到动态密码后,输出到 stdout 即可。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1057377

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX