needhelp
← Back to blog

ssh-keysign-pwn: Lendo arquivos de propriedade raiz por meio de um bug de lógica ptrace

by xingwangzhe
Linux
Núcleo
Segurança
Qualis
rastreamento
CVE

ssh-keysign-pwn: Um bug lógico de seis anos na função __ptrace_may_access() do kernel, relatado pela Qualys e corrigido por Linus Torvalds em 14 de maio de 2026. Usuários sem privilégios podem ler arquivos de propriedade do root, incluindo chaves privadas do host SSH e /etc/shadow. Todos os kernels pré-31e62c2ebbfd afetados.


Outro

Maio de 2026 não foi gentil com o kernel Linux. Dirty Frag, Fragnesia e agora—ssh-keysign-pwn—divulgado pela Qualys em 14 de maio e corrigido por Linus Torvalds no mesmo dia.

Este é diferente da família “copiar algo para o cache da página”. É um bug lógico puro em __ptrace_may_access(), a função do kernel que decide se um processo pode inspecionar outro.

Métrica Valor
Relatado por Assessoria de Segurança Qualys
Corrigido por Linus Torvalds
Corrigir confirmação 31e62c2ebbfd
Esperado por ~6 anos
Primeiro sinalizado por Jann Horn (Google), outubro de 2020
PoC publicado por _Doente
Impacto Leia arquivos de propriedade do root como usuário sem privilégios
Explorar complexidade 100–2.000 spawns por roubo bem-sucedido

Como funciona

O bug reside em __ptrace_may_access(). Esta função é o guardião da introspecção do processo – ela verifica se um processo tem permissão para bisbilhotar o estado de outro processo.

Há um caso especial: quando task->mm == NULL (o processo de destino não tem descritor de memória - acontece quando um thread está saindo ou para threads do kernel), a função ignora totalmente a verificação de dumpable.

Aqui está o caminho do código que torna isso explorável:

  1. Um processo chama do_exit() para encerrar
  2. do_exit() executa exit_mm() primeiro - isso destrói o descritor de memória (mm)
  3. Em seguida, ele executa exit_files() — mas os descritores de arquivo ainda estão ativos neste ponto
  4. Com task->mm == NULL, mas os descritores de arquivo ainda abertos, pidfd_getfd(2) pode roubar esses fds se o uid do chamador corresponder

Normalmente, as verificações de acesso ptrace impediriam que um processo menos privilegiado alcançasse os identificadores de arquivo abertos de um processo raiz. Mas o desvio mm == NULL elimina a verificação descartável e pidfd_getfd(2) faz o resto.

Esta é uma corrida TOCTOU clássica, mas a janela é ampla o suficiente para que o PoC acerte em 100–2.000 tentativas.

Explorar alvos

Duas ferramentas foram publicadas:

sshkeysign_pwn — tem como alvo ssh-keysign, um binário auxiliar que assina desafios de autenticação de host. O binário abre arquivos de chave do host SSH (/etc/ssh/ssh_host_{ecdsa,ed25519,rsa}_key, modo 0600) antes de chamar permanently_set_uid() para eliminar privilégios. Em seguida, ele verifica se EnableSSHKeysign está definido em sshd_config — caso contrário, ele sai com a chave fds ainda aberta. Este design está no OpenSSH desde 2002.

chage_pwn — alvos chage -l <user>. O binário abre /etc/shadow via spw_open(O_RDONLY) e depois chama setreuid(ruid, ruid) — eliminando todos os privilégios, pois ambos os argumentos são o uid real. Na janela de corrida entre a queda do privilégio e o fechamento do arquivo, o fd pode ser roubado.


Linha do tempo

Data Evento
~2020 Jann Horn identifica o padrão de roubo de FD e propõe um patch (não mesclado)
14/05/2026 Qualys relata a vulnerabilidade; Linus Torvalds confirma a correção (31e62c2ebbfd)
14/05/2026 Brad Spengler (@spendergrsec) publica análise
14/05/2026 _SiCk publica exploits PoC no GitHub
15/05/2026 Qualys envia divulgação para oss-security

A lacuna entre a proposta de patch de Jann Horn para 2020 e o relatório de 2026 da Qualys é notável. A correção foi elaborada há cinco anos, mas nunca foi implementada no upstream.


A correção

Linus confirmou a correção como commit 31e62c2ebbfd. Sua mensagem de commit observou:

“temos um caso especial estranho: ptrace_may_access() usa ‘dumpable’ para verificar várias outras coisas de forma totalmente independente do MM (normalmente usando explicitamente sinalizadores como PTRACE_MODE_READ_FSCREDS), inclusive para threads que não possuem mais uma VM (e talvez nunca tenham tido, como a maioria dos threads de kernel). Não é para isso que esse sinalizador foi projetado, mas é o que é.”

O patch ajusta o comportamento do ptrace para lidar adequadamente com o caso mm == NULL. Ele fecha efetivamente a janela de bypass.

Verifique seu kernel

Terminal window
# Check if your kernel has the fix
uname -r
# Fixed kernels have commit 31e62c2ebbfd included
# All kernels before 2026-05-14 are vulnerable

O que torna este interessante

Três coisas se destacam:

  1. Foi consertado no mesmo dia em que foi relatado. Linus resolveu isso em horas. Isso é incomumente rápido para uma correção do kernel, sugerindo que o patch foi simples assim que o bug foi compreendido.

  2. Jann Horn descobriu isso em 2020. A comunidade tinha uma proposta de patch nos arquivos da lista de discussão por cinco anos. A forma do roubo FD era conhecida, mas ninguém a forçou.3. Os alvos são antigos. O padrão de saída do fd de ssh-keysign data de 2002. A sequência spw_open + setreuid de chage é igualmente de longa data. Este não é um bug no SSH ou shadow-utils - é um bug do kernel que transforma os padrões de manipulação de fd existentes em binários privilegiados.

Esta também é a terceira grande vulnerabilidade do kernel Linux em maio de 2026, depois de Copy Fail e Dirty Frag. O ritmo de divulgação está se acelerando — em parte porque as ferramentas de auditoria assistidas por IA estão encontrando bugs antigos com mais rapidez e, em parte, porque o ecossistema de divulgação está se fragmentando (embargos sendo quebrados, PoCs lançados antes dos patches).


Referências

Share this page