Sshcli
SSH CLI - Asynchronous batch attack based on ssh connection
Install / Use
/learn @c0mentropy/SshcliREADME
SSH CLI
前言
在通过某种方式批量处理SSH连接时,总是会很麻烦,亦或者是某种场合下的SSH弱口令。总之,基于SSH批量执行命令还是颇为重要的(我感觉是),所以便有了该工具:SSH CLI。
安装
使用git克隆到本地,pip install下载
git clone https://github.com/c0mentropy/sshcli.git
cd ./sshcli
pip install .
或在Releases中下载tar.gz文件,然后pip install下载
示例:
wget -c https://github.com/c0mentropy/sshcli/releases/download/v1.0.6/sshcli-1.0.6.tar.gz
pip install sshcli-1.0.6.tar.gz
说明
项目基于的所有库如下(现均已写在setup.py中):
如前期版本有部分库缺少则自行安装即可。
"click", "asyncssh", "aioconsole", "colorlog", "prompt_toolkit", "pyyaml"
该项目在Python 3.12.7下开发,在Python 3.13.1下测试。若在其他python仍在维护版本(python3.8以上)运行该项目,如有问题,可提交issues

简介
当前版本界面展示:

该脚本基于asyncssh库实现的异步ssh连接处理。具体如下:
sshcli --help

param:
--hosts-file # 需要批量连接的hosts文件,默认格式为:ip:port
--network-segment # 需要批量连接的网段
--username # 需要批量连接的ssh登录用户名
--password # 需要批量连接的ssh登录的密码
--private-key-file # 需要批量连接的ssh的密钥路径
--port # 如果hosts文件中的格式为:ip,没有端口,则会使用该参数统一设置端口
--timeout # 执行命令的timeout,避免由于某个命令卡住而导致后续无法进行
--log-config-file # 日志的配置文件路径
--log-level # 输出日志等级
--save / --no-save # 是否需要将加载信息保存成json文件
--save-user-datas-file # 保存成json文件的路径
--proxy / --no-proxy # 是否使用代理
--proxy-config-file # 代理的配置文件路径,(如配置文件里为空,则从环境变量读取)
由于该工具我选择使用click来实现,click提供的help文档的Commands顺序是按字母排序的。所以我按照我实现的顺序来编写README,和上述脚本运行的帮助文档顺序不同还望见谅。
Upload File
顾名思义,这是一个上传文件模块。
sshcli uploadfile --help

param:
--local-path # 是需要上传的本地文件路径
--remote-path # 是上传到远程服务器的路径
Download File
同Upload File,这是一个下载文件模块。

param:
--remote-path # 是下载的远程服务器的路径
--local-path # 是需要下载到本地文件路径
注: 与上传文件不同的是,在处理批量ssh连接时,如果要批量下载某种配置文件等,则为了避免文件冲突,所以在选择完保存路径之后,会在该路径下创建对应host名称的文件夹,下载后存放在对应的文件夹下。
Add User
这是一个创建新用户的模块。
sshcli adduser --help

param:
--new-username # 创建新用户的用户名
--new-password # 创建新用户的密码
--root / --no-root # 创建root权限用户,或者普通用户
Change Password
这是一个更改用户密码的模块。
sshcli changepassword --help

param:
--new-password # 更改后的新密码
--user # 需要更改密码的用户名
Bind Shell
这是一个绑定正向连接的模块。
sshcli bindshell --help

param:
--new-port # 绑定一个shell到指定端口
--shell # 需要绑定的shell类型
补充:为什么没有做反弹shell,原因是批量处理的时候,接收端口应该怎么做呢,总不能全弹到同一个端口上吧。但不影响,如果需要反弹shell,我还有另外一个基于golang写的轻量化工具。可以配合使用。
Ln sshd
这是一个建立软连接的模块,是将sshd软连接到一个名为su的文件上,再绑定该程序到一个端口上,即可实现任意密码登录ssh。
sshcli lnsshd --help

param:
--new-port # 将软连接的su绑定一个指定端口
--path # 将sshd软连接到哪个路径下
Interactive
这是一个建立交互的模块。
sshcli interactive --help

进入交互模块,实现的逻辑是,首先通过异步连接先将所有ssh连接成conn对象字典保存起来,然后进行交互操作。具体的使用方式和命令行类似,详见下图

通过help查看命令帮助列表,其中会多一个shell功能,是选择一个host进入shell单独操作。

通过exit退出该shell,回到统一控制界面。

Query permissions
这是一个查询部分信息的模块。(后续可添加查询的内容)
sshcli queryperm --help

示例:

Exec
这是一个执行命令的模块。主要是方便和其他脚本结合使用时候,可以exec执行命令。
sshcli -hf ./hosts.json exec -cmd whoami

示例:

Command Server
在server目录中存在一个静态链接工具,command_server,其功能详见该目录。
示例
由于命令较为繁琐,所以这里给出一些常用示例,方便使用。
首先,所有各自命令都有自己的help帮助文档,可自行查看参数,使用方法基本类似,不一一举例说明。
使用ip段和固定端口传递
sshcli -ns 172.17.0.2/29 -name root -pwd root123 -level debug --proxy interactive

**注:**爆红的error是这两个ip的容器不存在,所以失败了。
使用json传递
强烈建议使用.json格式文件当作hosts file传递。
sshcli -hf ./hosts.json -level debug interactive

hosts.json示例:
{
"192.168.75.142:8301": {
"username": "root",
"password": "",
"private_key_path": "/root/.ssh/id_rsa_1"
},
"192.168.75.142:8302": {
"username": "root",
"password": "",
"private_key_path": "/root/.ssh/id_rsa_1"
},
"192.168.75.142:8303": {
"username": "root",
"password": "admin123",
"private_key_path": "/root/.ssh/id_rsa"
},
"192.168.75.142:8304": {
"username": "root",
"password": "root123",
"private_key_path": ""
}
}
文件说明:
- 如果private_key_path为空字符串,则会使用用户名密码的形式,此时password就是密码。
- 如果存在private_key_path字段,则password字段为密钥登录时候的passphrase验证,无需验证则留空。
- 如果省略端口,则为默认的22端口,当然也可以
-port指定固定端口。
使用txt传递 && 保存数据
通过.txt等其他方式传递时,可以save保存成.json文件
sshcli -hf ./hosts.txt -name root -pwd root123 -level debug --save -save-udf tests_save.json interactive

hosts.txt示例:
192.168.75.142:8301
192.168.75.142:8302
192.168.75.142:8303
192.168.75.142:8304
保存后的tests_save.json是:
{
"192.168.75.142:8301": {
"username": "root",
"password": "root123",
"private_key_path": ""
},
"192.168.75.142:8302": {
"username": "root",
"password": "root123",
"private_key_path": ""
},
"192.168.75.142:8303": {
"username": "root",
"password": "root123",
"private_key_path": ""
},
"192.168.75.142:8304": {
"username": "root",
"password": "root123",
"private_key_path": ""
}
}
使用proxy代理
这里会从配置文件中读取,或者从环境变量中读取代理配置。也可以结合其他代理工具使用如proxychains4
sshcli -hf ./proxy_hosts.json -level debug --proxy interactive

p4 sshcli -hf ./proxy_hosts.json -level debug interactive

proxy_hosts.json示例:
{
"172.17.0.2:22": {
"username": "root",
"password": "root123",
"private_key_path": ""
},
"172.17.0.3:22": {
"username": "root",
"password": "root123",
"private_key_path": ""
},
"172.17.0.4:22": {
"username": "root",
"password": "root123",
"private_key_path": ""
},
"172.17.0.5:22": {
"username": "root",
"password": "root123",
"private_key_path": ""
}
}
特性
伪终端
提供了一个良好的伪终端交互界面

长度适配:
这里可以发现,选择session的时候可以输入id,也可输入host的值。

输入
在部分输入交互处,提供良好的输入交互系统,可以使用"上、下"查找上次的输入,也可以左右移动更改命令等。
示例1:

示例2:

API
提供api模式调用,方便使用。~~(注:目前仅开放了interactive的api)~~
重写了识别api的部分,在sshcli类中,函数名定义为:run_function_name即以run_起始的方法都自动生成api接口。
示例:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from sshcli import SSHCli
if __name__ == '__main__':
sshcli = SSHCli(hosts_file="./hosts.json", log_level='debug')
sshcli.api.interactive()

Related Skills
node-connect
351.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
110.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
351.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
351.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
