A distribuição de sistema operacional de código aberto OpenBSD é bem conhecida entre os administradores de sistemas, especialmente aqueles que gerenciam servidores, por seu foco em segurança em vez de velocidade, recursos e front-ends sofisticados.
Apropriadamente, talvez, seu logotipo seja um baiacu - inflado, com suas pontas prontas para repelir qualquer hacker astuto que possa aparecer.
Mas a equipe do OpenBSD é provavelmente mais conhecida não por toda a sua distro, mas pelo kit de ferramentas de acesso remoto OpenSSH que foi escrito no final dos anos 1990 para inclusão no próprio sistema operacional.
SSH, abreviação de capsula segura, foi originalmente criado pelo cientista da computação finlandês Tatu Ylönen em meados da década de 1990, na esperança de afastar os administradores de sistema do hábito arriscado de usar o protocolo Telnet.
O problema com o Telnet
O Telnet era notavelmente simples e eficaz: em vez de conectar fios físicos (ou usar um modem através de uma linha telefônica) para fazer uma conexão de teletipo a servidores remotos, você usava uma conexão de rede TELetype.
Basicamente, os dados que normalmente fluiriam de um lado para o outro por uma conexão serial dedicada ou linha telefônica discada eram enviados e recebidos pela Internet, usando uma conexão de rede TCP com comutação de pacotes em vez de um link ponto a ponto com comutação de circuitos. .
Mesmo sistema de login familiar, conexões mais baratas, sem necessidade de linhas de dados dedicadas!
A grande falha no Telnet, é claro, era a total falta de criptografia, de modo que farejar sua sessão de terminal exata era trivial, permitindo que os crackers vissem todos os comandos que você digitava (até mesmo os erros que você cometeu e todas as vezes que você apertou [Backspace]
), e cada byte de saída produzido…
…e, claro, seu nome de usuário e senha no início da sessão.
Qualquer pessoa em seu caminho de rede pode não apenas reconstruir facilmente suas sessões de administrador de sistema em tempo real em sua própria tela, mas provavelmente também adulterar sua sessão modificando os comandos que você enviou para o servidor remoto e fingindo que as respostas voltam para que você não perceba o subterfúgio.
Eles podem até configurar um servidor impostor, atraí-lo para ele e tornar surpreendentemente difícil para você identificar o engano.
Criptografia forte FTW
O SSH de Ylönen visava adicionar uma camada de criptografia forte e autenticação a cada extremidade de uma sessão do tipo Telnet, criando um capsula segura (é isso que o nome significa, se você já se perguntou, embora quase todo mundo o chame ess-ess-aitch nos dias de hoje).
Foi um sucesso instantâneo e o protocolo foi rapidamente adotado por administradores de sistema em todos os lugares.
O OpenSSH logo se seguiu, como mencionamos acima, aparecendo pela primeira vez no final de 1999 como parte do OpenBSD 2.6 liberar.
A equipe do OpenBSD queria criar uma implementação gratuita, confiável e de código aberto do protocolo que eles e qualquer outra pessoa poderia usar, sem nenhuma das complicações comerciais ou de licenciamento que sobrecarregaram a implementação original de Ylönen nos anos imediatamente após seu lançamento.
De fato, se você executar o servidor SSH do Windows e se conectar a ele a partir de um computador Linux agora, quase certamente estará contando com a implementação do OpenSSH em ambas as extremidades.
O protocolo SSH também é usado em outros serviços populares de cliente-servidor, incluindo SCP e SFTP, abreviação de cópia segura e FTP seguro respectivamente. SSH significa vagamente, “conecte-se com segurança e execute um comando SHell na outra extremidade”, normalmente para logins interativos, porque o programa Unix para um shell de comando geralmente é /bin/sh
. SCP é semelhante, mas para copiar arquivos, porque o comando Unix file-copy é geralmente chamado /bin/cp
, e SFTP é nomeado da mesma maneira.
OpenSSH não é o único kit de ferramentas SSH na cidade.
Outras implementações bem conhecidas incluem: libssh2, para desenvolvedores que desejam criar suporte SSH diretamente em seus próprios aplicativos; Queda de urso, um servidor SSH simplificado do codificador australiano Matt johnston isso é amplamente encontrado nos chamados dispositivos IoT (Internet of Things), como roteadores e impressoras domésticos; e PuTTY, uma coleção popular e gratuita de ferramentas relacionadas ao SSH para Windows do desenvolvedor independente de código aberto Simon Tatham na Inglaterra.
Mas se você é um usuário regular do SSH, quase certamente já se conectou a pelo menos um servidor OpenSSH hoje, até porque a maioria das distribuições contemporâneas do Linux o inclui como ferramenta de acesso remoto padrão, e a Microsoft oferece um cliente OpenSSH e um OpenSSH server como componentes oficiais do Windows atualmente.
Correção de bug duplamente gratuita
OpenSSH versão 9.2 acabou de sair, e o notas de lançamento relatório da seguinte forma:
Esta versão contém correções para [...] um problema de segurança de memória. Acredita-se que [este bug] não seja explorável, mas relatamos a maioria das falhas de memória acessíveis pela rede como bugs de segurança.
O erro afeta sshd
, o servidor OpenSSH (o -d
sufixo significa demônio, o nome Unix para o tipo de processo em segundo plano que o Windows chama de serviço):
sshd(8): corrija uma falha de memória dupla livre de pré-autenticação introduzida no OpenSSH 9.1. Acredita-se que isso não seja explorável e ocorre no processo de pré-autenticação não privilegiado que está sujeito ao chroot(2) e é ainda colocado em sandbox na maioria das principais plataformas.
Um bug double-free significa que um bloco de memória que você já devolveu ao sistema operacional para ser reutilizado em outras partes do seu programa…
…mais tarde será devolvido novamente por uma parte do programa que não é mais “proprietária” dessa memória, mas não sabe que não é.
(Ou devolvido deliberadamente a pedido do código que está tentando provocar o bug de propósito para transformar um vulnerabilidade em um explorar.)
Isso pode levar a bugs sutis e difíceis de resolver, especialmente se o sistema marcar o bloco liberado como disponível quando o primeiro free()
acontece, depois aloca para outra parte do seu código quando pede memória via malloc(
) e, em seguida, marca o bloco livre mais uma vez quando a chamada supérflua para free()
aparece.
Isso o deixa no tipo de situação que você experimenta quando faz check-in em um hotel que diz: “Oh, boas notícias! Achamos que estávamos lotados, mas outro hóspede decidiu fazer o check-out mais cedo, para que você possa ficar com o quarto dele.”
Mesmo que o quarto esteja bem limpo e preparado para novos ocupantes quando você entrar e, portanto, pareça que foi alocado corretamente para seu uso exclusivo, você ainda precisa confiar que o cartão-chave do hóspede anterior foi realmente cancelado corretamente e que o “ check-out antecipado” não era um ardil astuto para voltar mais tarde no mesmo dia e roubar seu laptop.
Correção de bug para correção de bug
Ironicamente, se você observar o histórico recente do código OpenSSH, verá que o OpenSSH tinha um bug modesto em uma função chamada compat_kex_proposal()
, usado para verificar que tipo de algoritmo de troca de chave usar ao configurar uma conexão.
Mas corrigir esse bug modesto introduziu uma vulnerabilidade mais grave.
A propósito, a presença do bug em uma parte do software que é usado durante a configuração de uma conexão é o que torna isso um chamado pré-autenticação acessível pela rede vulnerabilidade (ou bug pré-autenticação como diminutivo).
O bug do double-free acontece no código que precisa rodar depois de um cliente iniciou uma sessão remota, mas antes qualquer acordo de chave ou autenticação ocorreu, então a vulnerabilidade pode, em teoria, ser acionada antes que quaisquer senhas ou chaves criptográficas tenham sido apresentadas para validação.
No OpenSSH 9.0, compat_kex_proposal
parecia algo assim (muito simplificado aqui):
char* compat_kex_proposal(char* suggestion) { if (condition1) { return suggestion; } if (condition2) { suggestion = allocatenewstring1(); } if (condition3) { suggestion = allocatenewstring2(); } if (isblank(suggestion)) { error(); } return suggestion; }
A ideia é que o chamador passe em seu próprio bloco de memória contendo uma string de texto sugerindo uma configuração de troca de chave e receba de volta uma aprovação para usar a própria sugestão que enviou ou uma string de texto recém-alocada com uma sugestão atualizada .
O bug é que, se a condição 1 for falsa, mas as condições 2 e 3 forem verdadeiras, o código aloca dois novas cadeias de texto, mas apenas retorna um.
O bloco de memória alocado por allocatenewstring1()
nunca é liberado e, quando a função retorna, seu endereço de memória é perdido para sempre, então não há como nenhum código free()
isso no futuro.
Esse bloco é essencialmente abandonado, causando o que é conhecido como um vazamento de memória.
Com o tempo, isso pode causar problemas, talvez até forçando o desligamento do servidor para se recuperar da sobrecarga de memória.
No OpenSSH 9.1, o código foi atualizado na tentativa de evitar alocar duas strings, mas abandonar uma delas:
/* Always returns pointer to allocated memory, caller must free. */ char* compat_kex_proposal(char* suggestion){ char* previousone = NULL; if (condition1) { return newcopyof(suggestion); } if (condition2) { suggestion = allocatenewstring1(); } if (condition3) { previousone = suggestion; suggestion = allocatenewstring2(); } free(previousone); } if (isblank(suggestion()) { error(); } return suggestion; }
Isso tem o bug double-free, porque se a condição 1 e a condição 2 forem ambas falsas, mas a condição 3 for verdadeira, então o código aloca uma nova string para enviar de volta como sua resposta…
…mas libera incorretamente a string que o chamador transmitiu originalmente, porque a função allocatenewstring1()
nunca é chamado para atualizar a variável suggestion
.
A string de sugestão passada é a memória que pertence ao chamador, e que o chamador irá, portanto, liberar-se mais tarde, levando ao perigo de double-free.
No OpenSSH 9.2, o código ficou mais cauteloso, rastreando todos os três possíveis blocos de memória usados: o original suggestion
(memória pertencente a outra pessoa) e duas possíveis novas strings que podem ser alocadas no caminho:
/* Always returns pointer to allocated memory, caller must free. */ char* compat_kex_proposal(char* suggestion) { char* newone = NULL; char* newtwo = NULL; if (condition1) { return newcopyof(suggestion); } if (condition2) { newone = allocatenewstring1(); } if (condition3) { newtwo = allocatenewstring2(); } free(newone); newone = newtwo; } if (isblank(newone)) { error(); } return newone; }
Se a condição 1 for verdadeira, uma nova cópia da string passada é usada, para que o chamador possa mais tarde free()
a memória de suas strings passadas sempre que quiserem.
Se passarmos da condição 1 e a condição 2 for verdadeira, mas a condição 3 for falsa, então a sugestão alternativa criada por allocatenewstring1()
é devolvido, e o passado suggestion
string é deixado sozinho.
Se a condição 2 for falsa e a condição 3 for verdadeira, então uma nova string é gerada e retornada, e o passado suggestion
string é deixado sozinho.
Se ambas as condições 2 e 3 forem verdadeiras, duas novas strings serão alocadas ao longo do caminho; o primeiro é liberado porque não é necessário; o segundo é devolvido; e o passado suggestion
string é deixado sozinho.
Você pode RTxM para confirmar que se você ligar free(newone)
quando newone
is NULL
, então “nenhuma operação é executada”, porque é sempre seguro free(NULL)
. No entanto, muitos programadores ainda se protegem fortemente contra isso com códigos como if (ptr != NULL) { free(ptr); }
.
O que fazer?
Como sugere a equipe do OpenSSH, explorar esse bug será difícil, principalmente por causa dos privilégios limitados que o sshd
programa tem enquanto está configurando a conexão para uso.
No entanto, eles relataram isso como uma falha de segurança porque é isso, então certifique-se de atualizar para OpenSSH 9.2.
E se você estiver escrevendo código em C, lembre-se de que não importa o quanto você tenha experiência, é fácil errar no gerenciamento de memória…
…então tome cuidado lá fora.
(Sim, Rust e seus amigos modernos irão ajudá-lo a escrever o código correto, mas às vezes você ainda precisará usar C, e até mesmo o Rust não pode garantir pará-lo de escrever código incorreto se você programar imprudentemente!)
- Conteúdo com tecnologia de SEO e distribuição de relações públicas. Seja amplificado hoje.
- Platoblockchain. Inteligência Metaverso Web3. Conhecimento Ampliado. Acesse aqui.
- Fonte: https://nakedsecurity.sophos.com/2023/02/03/openssh-fixes-double-free-memory-bug-thats-pokable-over-the-network/