- Foi identificado um caso em que, em uma sessão SSH, centenas de pacotes eram enviados com uma única tecla pressionada, e a causa foi investigada
- A análise com
tcpdump mostrou que a maioria dos pacotes consistia em mensagens repetidas de 36 bytes, ocorrendo em intervalos de cerca de 20 ms
- A causa era o recurso de “ofuscação do timing das teclas pressionadas” (keystroke timing obfuscation), adicionado ao SSH em 2023, que envia vários pacotes de “chaff” (SSH2_MSG_PING) para ocultar o timing da digitação do usuário
- Ao desativar esse recurso ou modificar o servidor para que ele não anuncie a extensão
[email protected], o uso de CPU e de largura de banda caiu para menos da metade
- Este é um caso que mostra como um recurso de segurança do SSH pode se tornar uma carga significativa em aplicações em que o desempenho em tempo real é importante (ex.: jogos)
Descoberta do problema
- Durante testes da TUI de um jogo de alto desempenho executado via SSH, foi observado que uma única tecla pressionada gerava 270 pacotes
- No
tcpdump, 66% eram mensagens de 36 bytes, 33% eram TCP ACK, e o restante era uma pequena quantidade de outros dados
- Em média, eram 90 pacotes/segundo, com transmissão de dados a cada aproximadamente 11 ms
- Durante os testes, o servidor foi configurado incorretamente para enviar apenas a mensagem “your screen is too small”, e nesse caso o uso de CPU e de largura de banda caiu pela metade
- Como os dados do jogo não deveriam estar sendo transmitidos, o uso de CPU deveria ficar próximo de 0%, mas ainda permanecia em torno de 50%
- Isso levantou a possibilidade de haver sobrecarga de comunicação do próprio SSH
Processo de investigação
- Usando
tcpdump, foi feita uma comparação entre o tráfego SSH em funcionamento normal e em estado de erro
- Mesmo no estado de erro, pacotes de 36 bytes continuavam aparecendo em intervalos de 20 ms
- O mesmo padrão também foi confirmado no cliente SSH padrão do macOS
- A análise do arquivo pcap com Claude Code mostrou que
- Dos 413.703 pacotes totais, 66% tinham 36 bytes e 34% eram ACK de 0 byte
- O cliente SSH estava gerando os pacotes de forma ativa
Causa raiz
Como resolver
- No lado do cliente, é possível desativar o recurso com a opção
ObscureKeystrokeTiming=no
- Após aplicar a configuração, o uso de CPU e de largura de banda caiu bastante, mantendo a transmissão de dados normal
- Como medida no lado do servidor, a extensão
[email protected] deixou de ser anunciada na biblioteca SSH de Go
- Após reverter o commit relacionado e testar novamente, os resultados foram:
- uso de CPU 29.9% → 11.6%,
chamadas de sistema 3.10s → 0.66s,
operações criptográficas 1.6s → 0.11s,
largura de banda 6.5Mbit/s → 3Mbit/s
- O desempenho melhorou em mais de 50%
Experiência de depuração com LLM
- Com Claude Code, a análise de
tcpdump e tshark foi automatizada, permitindo restringir rapidamente a causa do problema
- Observando em tempo real o processo de execução dos comandos, foi possível manter um modelo mental da investigação
- Também houve a experiência de diferenças entre modelos, como o ChatGPT ter julgado incorretamente que o comportamento do SSH era “normal”
- LLMs não substituem todo o processo de resolução de problemas, mas mostraram alta eficiência como ferramenta auxiliar de análise
- Este é um caso em que a combinação do raciocínio humano com a análise de LLM resolveu um problema complexo de desempenho de rede
1 comentários
Comentários do Hacker News
Dá um pouco de medo fazer fork da biblioteca crypto do Go
Estou pensando em como manter meu pequeno patch seguro
Na verdade, acho que esse tipo de recurso deveria subir como uma opção da biblioteca ssh no upstream
Em ambientes não confiáveis, enviar pacotes chaff (ruído) como padrão faz sentido, mas muitas vezes também se quer economizar largura de banda
A solução correta seria adicionar uma opção para o servidor poder sinalizar ao cliente que “não precisa”, e o cliente aceitar isso ou emitir um aviso
Ele só se aplica a sessões TTY, e o cliente pode desativá-lo
Só que este caso é uma situação excepcional em que o servidor sabe de antemão que a conexão não é importante
Na maioria dos casos, o cliente espera que a configuração ObscureKeystrokeTiming seja respeitada
A biblioteca crypto é uma base de código com opiniões muito fortes, a ponto de nem permitir mudar a ordem das TLS cipher suites
Isso parece um caso de uso muito específico de SSH
Se for exposto amplamente demais, pode virar uma situação de “configurar e esquecer”, enfraquecendo a segurança
Também me comunicava por modem de 1200 bps, e modem de 56K era praticamente exagero de marketing
Por volta de 1994, eu trabalhava em uma faculdade militar no Reino Unido e tive meu primeiro contato com a WWW; na época pensei “isso é meio sem graça”
Olhando agora, é impressionante ver como os tempos mudaram
Foi a primeira vez que ouvi falar desse recurso de obfuscation, achei interessante
Ao depurar o comportamento do ssh, também é uma boa abordagem aplicar patch no cipher
Nonee olhar diretamente o conteúdo dos pacotesSe for um jogo de terminal em que segurança não importa e desempenho importa, talvez até valha considerar usar telnet
Eu não sabia que o SSH fazia isso
Entendo por que vem ativado por padrão, mas no meu ambiente provavelmente faz mais sentido desligar
Então estou pensando em definir
ObscureKeystrokeTiming=no. Existe algum motivo para eu não fazer isso?(1) Nem sempre é fácil distinguir quando alguém está digitando um segredo, e toda a atividade pode ser analisada por análise de padrões
(2) Esse é um ataque viável até no nível de um laboratório universitário — veja o artigo da USENIX e este estudo
(3) Em uma internet dominada por tráfego de vídeo, abrir mão de segurança para economizar alguns bytes de teclas não faz sentido
Se o atacante analisar o timing das teclas, talvez consiga inferir o comando e o padrão da senha criptografada
Claro, descriptografar é difícil porque a chave de sessão muda toda vez, mas a possibilidade existe
Eu também copio e colo a maioria das minhas senhas a partir de um gerenciador de senhas
A maioria das pessoas sente que não acontece nada mesmo depois de desativar recursos de segurança do SSH, mas isso é só sorte
Se o que você quer de verdade é desempenho, use Telnet; se quer segurança de verdade, uma boa combinação é ContainerSSH + OAuth2
Em 2004, eu fiz uma pesquisa para inferir comandos por meio da análise do intervalo entre teclas em sessões SSH
Veja a análise da época
O patch de 2023 acabou finalmente resolvendo esse problema
Material da apresentação
O tempo realmente voa
Não sei se o Claude realmente ajudou na depuração
O autor já parecia saber a direção, e o Claude só ficou concordando
Acho meio irritante quando o Claude fala coisas como “Holy Cow!”
Quando eu depuro o comportamento de sistemas com Claude, mesmo sem respostas diretas ele ajuda a organizar o entendimento e manter a motivação
Wiki de Rubber Duck Debugging
Pelo fato de o autor ter gostado da reação “holy cow” e colocado isso no blog, parece que o Claude leu bem o clima
Usar TCP_CORK pode reduzir a quantidade de pacotes sem adicionar latência
Desativar o TCP_NODELAY também é uma opção, mas isso tem o custo de aumentar a latência
Quando você aplica cork no socket, o kernel bufferiza os dados e os envia quando você faz uncork ou quando chega ao MSS
Em outras palavras, é uma forma de agrupar pacotes
Referência
Eu continuaria recebendo ping, mas talvez pudesse reduzir a frequência de envio de pong
Já usei TCP_NODELAY, mas a latência aumentou demais para o meu jogo
Post anterior no HN
Para fins de obfuscation, coalescing de latência parece inviável
Achei engraçada a expressão “The smoking gun!”
Não sou falante nativo de inglês, mas o Claude usa isso com frequência, então aprendi assim
Agora isso realmente está se espalhando como bordão
Acho ruim depender de LLM
Isso provavelmente teria sido resolvido mais rápido só olhando a captura de pacotes no Wireshark
O dissector de SSH é bem maduro
Mesmo capturando uma única tecla com tcpdump, aparecem centenas de pacotes criptografados
No fim, graças ao LLM o autor aprendeu algo interessante e compartilhou isso, então teve seu valor
Depois da mensagem NEWKEYS, ele já não consegue fazer parsing, e mesmo aplicando patch para criptografia
noneainda não interpreta o fluxo por completoAinda há espaço para melhorar
Aprender usando ferramentas também tem bastante valor
É difícil obter informação significativa só com captura simples de pacotes
Não vejo por que isso seria algo lamentável
Em 2023, o SSH adicionou um recurso de ofuscação do timing de teclas
Como é possível inferir caracteres pela velocidade de digitação, o SSH mistura pacotes chaff para que o atacante não consiga diferenciar
Mas isso parece uma abordagem errada
Se realmente quisessem, bastaria enviar todas as teclas em intervalos de 50 ms
A implementação atual agrupa em unidades de 20 ms, mas para de enviar chaff depois de um certo tempo sem digitação
O ponto central do SSH é a segurança, mas se você não precisa de segurança, fico em dúvida sobre por que usar SSH
Por exemplo, netcat (nc) já vem instalado por padrão na maioria das plataformas
No SSH também existem outros fatores, como desempenho e conveniência
O autor só está dizendo que o recurso de ofuscação de teclas (privacidade) é desnecessário para ele
Ele ainda pode querer manter criptografia e garantia de integridade
Ou seja, a escolha é manter a maior parte dos recursos de segurança do SSH e desligar apenas uma parte