← back
CVE-2025-32433criticalunder attackCWE-306

Erlang/OTP SSH Vulnerable to Pre-Authentication RCE

100Vexday Risk Score

Patch now. It under exploitation confirmed by CISA and has a working public exploit.

ssvc Actcvss 10epss 99%
from disclosure to weapon2 days
Published on NVDApr 16
1st PoC+2d
metasploitApr 16
CISA KEV+54d
exploitation probability
99%top 1% of all CVEs
observed exploitation
yesCISA + VulnCheck
75 public exploit(s)
Action required by CISAfederal deadline: 2025-06-30

Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.

Summary

Falha de CWE-306 (ausência de verificação de autenticação) no servidor SSH da biblioteca `ssh` do Erlang/OTP: a máquina de estados aceitava mensagens do protocolo de conexão SSH (channel open, channel request) antes de a etapa de autenticação terminar. Um atacante sem credenciais podia abrir um canal e enviar um `channel_request` do tipo "exec" pré-autenticação, que o servidor processava como se a sessão já estivesse autenticada — resultando em execução de código arbitrário na VM Erlang. Afeta qualquer aplicação que rode `ssh:daemon` (papel de servidor) da própria biblioteca `ssh` do OTP, o que inclui produtos embarcados e appliances (Cisco, NetApp, etc.) que usam essa stack para gerenciamento remoto.

Technical detail

A implementação da RFC 4252 exige que mensagens SSH com número >= 80 (mensagens do protocolo de conexão, RFC 4254, como SSH_MSG_CHANNEL_OPEN e SSH_MSG_CHANNEL_REQUEST) só sejam aceitas depois que a autenticação (SSH_MSG_USERAUTH_SUCCESS) for concluída. No módulo `ssh_connection.erl`, a função `handle_msg/4` despachava essas mensagens para o tratamento normal de canal independentemente do estado `#ssh{authenticated}`. Não havia nenhuma cláusula que verificasse `authenticated == false` antes de processar o payload — a checagem simplesmente não existia no fluxo de mensagens do lado servidor.

O patch (visível nos três commits de backport para os ramos 25/26/27) adiciona uma cláusula de guarda: quando o processo está no papel `server` e `Ssh#ssh.authenticated =:= false`, qualquer mensagem que não seja `ssh_msg_disconnect` gera um log de depuração e força a desconexão com `SSH_DISCONNECT_PROTOCOL_ERROR`. Ou seja, a correção não é um novo parser ou sanitização de input — é a adição da verificação de estado que faltava.

O vetor de exploração demonstrado no próprio caso de teste (`early_rce`) manda um `channel_open` seguido de um `channel_request` do tipo "exec" cujo payload é uma string Erlang (`lists:seq(1,10).` no teste, mas qualquer expressão válida na prática, incluindo chamadas como `os:cmd/1`). O manipulador padrão de "exec" da biblioteca avalia essa string como código Erlang via `erl_eval`, então o atacante controla diretamente a expressão executada dentro do processo BEAM do servidor — com os privilégios do processo Erlang, não de um shell do sistema, mas suficiente para chamar funções que executam comandos do SO.

O atacante controla: o payload textual do `channel_request` (a expressão Erlang a ser avaliada) e o timing do ataque (enviar antes de qualquer troca de autenticação). Não precisa de usuário, senha, chave pública nem de nenhuma configuração incomum do servidor SSH — o bug está na máquina de estados do protocolo, não em uma feature opcional.

How it’s exploited

Pré-requisito real é único e simples: acesso de rede TCP até uma porta onde um processo Erlang/OTP esteja rodando `ssh:daemon` (papel servidor). Não é necessário conhecer usuário ou senha, nem burlar autenticação por chave — o atacante nunca chega a enviar `SSH_MSG_USERAUTH_REQUEST`. Basta completar o handshake de transporte (hello, kexinit, key exchange) e, assim que o canal de criptografia está ativo, enviar `SSH_MSG_CHANNEL_OPEN` seguido de `SSH_MSG_CHANNEL_REQUEST` tipo "exec" com a expressão desejada como payload.

A complexidade é baixa (AC:L no CVSS): não há necessidade de manipular parâmetros de kex, nem contornar proteções adicionais — a única condição é que o servidor use o manipulador padrão de "exec" da lib (a mesma que avalia expressões Erlang), que é o comportamento de fábrica quando a aplicação não substitui o callback de shell/exec. Isso está confirmado por PoC pública (script Python que monta manualmente os pacotes SSH necessários) e por módulo Metasploit já disponível, o que reduz a barreira de exploração a praticamente zero. A CISA já confirma exploração ativa em produção (entrada no catálogo KEV).

O resultado final é execução de código dentro do runtime Erlang do servidor, com potencial de leitura/gravação de arquivos, pivotamento na rede e comprometimento total do host dependendo dos privilégios do processo BEAM — o CVSS 10.0 reflete justamente essa combinação de vetor de rede, sem autenticação, sem interação do usuário e impacto total de confidencialidade/integridade/disponibilidade.

Versions

Affected
Erlang/OTP com aplicação `ssh` >= 3.0.1, para OTP >= 17.0 (o advisory do fornecedor afirma que versões anteriores a OTP 17.0 também são provavelmente afetadas, mas não há comparação de versão bem definida para esse período pelo esquema de versionamento antigo). Afeta apenas o papel de servidor SSH (`ssh:daemon`); o papel de cliente não é impactado segundo o advisory.
Fixed in
OTP-27.3.3 (aplicação ssh 5.2.10), OTP-26.2.5.11 (aplicação ssh 5.1.4.8), OTP-25.3.2.20 (aplicação ssh 4.15.3.12).

How to protect

A correção definitiva é atualizar para OTP-27.3.3, OTP-26.2.5.11 ou OTP-25.3.2.20 (aplicação `ssh` nas versões 5.2.10, 5.1.4.8 ou 4.15.3.12, respectivamente) — qualquer versão igual ou superior à correspondente ao seu ramo já contém a checagem de estado de autenticação que faltava. O advisory do fornecedor also afirma que versões anteriores a OTP 17.0 provavelmente também são afetadas, mas não há comparação de versão bem definida para esse período (esquema de versionamento anterior).

Se a atualização não é viável imediatamente, o único paliativo real recomendado pelo fornecedor é desligar o servidor SSH da aplicação Erlang/OTP (não usar `ssh:daemon`) ou bloquear acesso à porta via firewall/controle de rede, restringindo a origem a hosts confiáveis. Isso não é um WAF ou regra de assinatura — a falha está no processamento de protocolo antes da autenticação, então qualquer conexão TCP alcançando a porta é suficiente para o ataque; segmentação de rede é o controle compensatório efetivo.

O que não funciona: trocar chaves de host, desabilitar métodos de autenticação específicos (senha vs chave pública) ou reforçar políticas de autenticação não mitiga nada, porque o ataque nunca chega à fase de autenticação — ele explora justamente a ausência da checagem antes dela. Restringir os tipos de canal/exec permitidos na configuração do daemon também não é confirmado como mitigação eficaz, já que o bug está na aceitação da mensagem antes da fase de auth, não no conteúdo do payload em si.

How to detect

O tráfego SSH é criptografado após a troca de chaves, então não é possível inspecionar o conteúdo do `channel_request` "exec" via captura de pacotes de rede sem decriptação — a assinatura de exploração não é visível em NIDS tradicional além de metadados de timing (canal aberto e requisição de exec logo após o key exchange, sem troca de `SSH_MSG_USERAUTH_*` completa). Em ambientes já corrigidos (pós-patch), o próprio código de defesa gera um log de depuração com a mensagem "Connection terminated. Unexpected message for unauthenticated user" via `?LOG_DEBUG`, seguido de desconexão com código de erro de protocolo — presença recorrente desse log é forte indício de tentativas de exploração contra uma instância já atualizada.

Em instâncias não corrigidas não há sinal de aplicação equivalente, porque o servidor simplesmente processa o comando como legítimo; o único rastro provável é comportamental — processos ou comandos inesperados originados do processo BEAM/erlang, conexões SSH cuja sessão nunca completou autenticação nos logs de auditoria do sistema, ou uso do PoC/módulo Metasploit público (que segue o padrão hello → kexinit → channel_open → channel_request exec) capturável em honeypots ou telemetria de fluxo caso a decriptação esteja disponível.

Researched and written with AI from the vendor advisory and public analysis, with the sources above. Always confirm the fixed version in the official advisory before acting.
Erlang/OTP is a set of libraries for the Erlang programming language. Prior to versions OTP-27.3.3, OTP-26.2.5.11, and OTP-25.3.2.20, a SSH server may allow an attacker to perform unauthenticated remote code execution (RCE). By exploiting a flaw in SSH protocol message handling, a malicious actor could gain unauthorized access to affected systems and execute arbitrary commands without valid credentials. This issue is patched in versions OTP-27.3.3, OTP-26.2.5.11, and OTP-25.3.2.20. A temporary workaround involves disabling the SSH server or to prevent access via firewall rules.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Affected products
erlang · otp
public PoCs found75
githubgithub.com/ProDefense/CVE-2025-32433142githubgithub.com/omer-efe-curkus/CVE-2025-32433-Erlang-OTP-SSH-RCE-PoC16githubgithub.com/NiteeshPujari/CVE-2025-32433-PoC7githubgithub.com/0xPThree/cve-2025-324336githubgithub.com/ekomsSavior/POC_CVE-2025-324335githubgithub.com/m0usem0use/erl_mouse5githubgithub.com/0x7556/CVE-2025-324333githubgithub.com/exa-offsec/ssh_erlangotp_rce3githubgithub.com/dollarboysushil/CVE-2025-32433-Erlang-OTP-SSH-Unauthenticated-RCE3githubgithub.com/darses/CVE-2025-324333githubgithub.com/LemieOne/CVE-2025-324333githubgithub.com/yonathanpy/CVE-2025-32433.py2githubgithub.com/joshuavanderpoll/cve-2025-324332githubgithub.com/AntonieSoga/Erlang-OTP-PoC_CVE-2025-324332githubgithub.com/mirmeweu/cve-2025-324332githubgithub.com/Know56/CVE-2025-324331githubgithub.com/teamtopkarl/CVE-2025-324331githubgithub.com/iteride/CVE-2025-324331githubgithub.com/becrevex/CVE-2025-324331githubgithub.com/bilalz5-github/Erlang-OTP-SSH-CVE-2025-324331githubgithub.com/ODST-Forge/CVE-2025-32433_PoC0githubgithub.com/Epivalent/CVE-2025-32433-detection0githubgithub.com/meloppeitreet/CVE-2025-32433-Remote-Shell0githubgithub.com/ps-interactive/lab_CVE-2025-324330githubgithub.com/MrDreamReal/CVE-2025-324330githubgithub.com/abrewer251/CVE-2025-32433_Erlang-OTP_PoC0githubgithub.com/vigilante-1337/CVE-2025-324330githubgithub.com/te0rwx/CVE-2025-32433-Detection0githubgithub.com/Mdusmandasthaheer/CVE-2025-324330githubgithub.com/l1nuxkid/CVE-2025-32433-exploit0githubgithub.com/soltanali0/CVE-2025-32433-Eploit0githubgithub.com/giriaryan694-a11y/cve-2025-32433_rce_exploit0githubgithub.com/blackcat4347/CVE-2025-32433-available-for-windows0githubgithub.com/carlosalbertotuma/CVE-2025-324330githubgithub.com/0xBlackash/CVE-2025-324330githubgithub.com/leehunkoo/hk_CVE-2025-324330githubgithub.com/chuzouX/CVE-2025-32433-Exploit-edited0githubgithub.com/dampedcoast/Exploiting-a-vulnerability-using-reverse-shell0cve_referencegithub.com/ProDefense/CVE-2025-32433/blob/main/CVE-2025-32433.pyunverifiedvulncheckvulncheck.com/xdb/a61e0c6ed8a8unverifiedvulncheckvulncheck.com/xdb/874f94accfdeunverifiedvulncheckvulncheck.com/xdb/a2f1151c609aunverifiedvulncheckvulncheck.com/xdb/ec3bcdccec72unverifiedvulncheckvulncheck.com/xdb/42214d962233unverifiedvulncheckvulncheck.com/xdb/822dbe209d89unverifiedvulncheckvulncheck.com/xdb/22d7bf70f177unverifiedvulncheckvulncheck.com/xdb/49e3a7890ab8unverifiedvulncheckvulncheck.com/xdb/04468c21f876unverifiedvulncheckvulncheck.com/xdb/734f3d7eff96unverifiedvulncheckvulncheck.com/xdb/774a5554920funverifiedvulncheckvulncheck.com/xdb/a78d51fa522eunverifiedvulncheckvulncheck.com/xdb/839147304502unverifiedvulncheckvulncheck.com/xdb/0b33fe6d7d52unverifiedvulncheckvulncheck.com/xdb/38c75d4fe3dfunverifiedvulncheckvulncheck.com/xdb/6b216fd69575unverifiedvulncheckvulncheck.com/xdb/d7301295748aunverifiedvulncheckvulncheck.com/xdb/0e9bd89eb6d9unverifiedvulncheckvulncheck.com/xdb/86ebf09be56aunverifiedvulncheckvulncheck.com/xdb/f113515d8d4eunverifiedvulncheckvulncheck.com/xdb/69cf5f0d4eabunverifiedvulncheckvulncheck.com/xdb/5d58dcd1c530unverifiedvulncheckvulncheck.com/xdb/565faeb39625unverifiedvulncheckvulncheck.com/xdb/e71bdbbefa5aunverifiedvulncheckvulncheck.com/xdb/eb1588dc5012unverifiedvulncheckvulncheck.com/xdb/a9222b177319unverifiedvulncheckvulncheck.com/xdb/6902aa2406ccunverifiedvulncheckvulncheck.com/xdb/ee86353aa562unverifiedvulncheckvulncheck.com/xdb/1dbe3f1ab0b2unverifiedvulncheckvulncheck.com/xdb/c117b927dc2bunverifiedvulncheckvulncheck.com/xdb/4021c20bae31unverifiedvulncheckvulncheck.com/xdb/6362122abe51unverifiedvulncheckvulncheck.com/xdb/52fa692c3246unverifiedvulncheckvulncheck.com/xdb/938bb25869efunverifiedvulncheckvulncheck.com/xdb/cf5a72dc6cf9unverifiedvulncheckvulncheck.com/xdb/963c3b33eb36unverified
⚠ Public resources, to assess the exposure of systems you control or are authorized to test. Test only with authorization.