Em resumo: Para encontrar chaves SSH desconhecidas, tem de verificar todos os ficheiros authorized_keys do servidor, não só o de root. Apure com sshd -T que ficheiros o seu serviço SSH lê, liste as impressões digitais de cada chave e compare-as com as chaves conhecidas. Primeiro guardar as entradas estranhas, depois removê-las e a seguir reforçar o acesso.
A chave que sobrevive a qualquer mudança de palavra-passe
Depois de um incidente, muitos operadores alteram primeiro todas as palavras-passe. Contra uma das portas dos fundos mais discretas isso não ajuda: uma chave pública adicional num ficheiro authorized_keys. Quem possui a chave privada correspondente autentica-se sem palavra-passe, até alguém encontrar a linha.
As chaves SSH desconhecidas pertencem por isso aos indícios que depois de uma execução de código devem ser sempre verificados. Para o PHP2Shell não existem Indicators of Compromise publicados e confirmados; a deteção assenta na análise de comportamento. Uma chave estranha não é uma prova específica do PHP2Shell, mas é um sinal claro de que alguém queria um acesso duradouro. Outros indícios descreve-os Já fui comprometido?.
Onde estão as chaves SSH no servidor
O OpenSSH lê, segundo a documentação, por defeito dois ficheiros no diretório pessoal de cada utilizador: .ssh/authorized_keys e .ssh/authorized_keys2. O segundo é muitas vezes esquecido. A definição pode ser alterada e, com AuthorizedKeysCommand, o servidor pode até obter chaves de um programa externo. Verifique por isso primeiro o que realmente vale no seu servidor:
# Mostrar a configuração SSH efetiva (apenas leitura)
sudo sshd -T | grep -iE '^(authorizedkeysfile|authorizedkeyscommand|permitrootlogin|passwordauthentication|pubkeyauthentication)'
# Ficheiros de configuração adicionais e blocos Match
ls -la /etc/ssh/sshd_config.d/ 2>/dev/null
sudo grep -rn -iE '^\s*(Match|AuthorizedKeys)' /etc/ssh/
Um local especial é o diretório pessoal do utilizador do servidor web. No Debian e no Ubuntu, para o www-data é muitas vezes /var/www. Se este diretório for gravável pelo PHP, código introduzido pode criar aí um .ssh/authorized_keys. Se a autenticação então resulta depende da shell de login e das definições SSH, mas o próprio ficheiro já é um sinal de alarme.
Nem toda a entrada desconhecida é maliciosa. Ferramentas de deployment, serviços de cópia de segurança ou prestadores anteriores depositam chaves próprias. Essas entradas devem, porém, ter um proprietário e uma finalidade conhecidos.
Verificar authorized_keys: passo a passo
Os comandos seguintes não alteram nada. Listam todos os ficheiros de chaves dos utilizadores e mostram a impressão digital de cada chave:
# Todos os ficheiros authorized_keys nos diretórios pessoais de todos os utilizadores
getent passwd | cut -d: -f1,6 | while IFS=: read -r user home; do
for f in "$home/.ssh/authorized_keys" "$home/.ssh/authorized_keys2"; do
[ -f "$f" ] && echo "== $user: $f" && sudo ls -la --time-style=full-iso "$f"
done
done
# Mostrar impressões digitais e comentários de um ficheiro
sudo ssh-keygen -lf /root/.ssh/authorized_keys
# Outros ficheiros de chaves fora dos locais habituais
sudo find / -xdev -name 'authorized_keys*' 2>/dev/null
Percorra o resultado com esta lista de verificação:
- Cada chave pertence a uma pessoa ou serviço conhecido? Compare as impressões digitais, não apenas o comentário.
- Algum utilizador tem chaves que não devia ter? Por exemplo o utilizador do servidor web, da base de dados ou contas de serviço.
- Há opções antes da chave? As entradas com
command=executam um comando fixo em cada autenticação. É legítimo para cópias de segurança, mas também um esconderijo. - Quando foi alterado o ficheiro pela última vez? Uma data de alteração depois de 17/10/2026, a primeira tentativa de ataque do PHP2Shell observada segundo relatos dos meios de comunicação, merece especial atenção. Os carimbos de data/hora podem, porém, ser falsificados.
- Proprietário e permissões coincidem? Um ficheiro que pertence a um utilizador diferente do do diretório pessoal chama a atenção.
Remover chaves estranhas em segurança
Antes de apagar uma linha, guarde o ficheiro com carimbo de data/hora e soma de verificação fora do servidor. Anote a impressão digital da chave estranha. Ajuda mais tarde na questão de saber se a mesma chave aparece também noutros servidores, por exemplo numa agência com muitos sistemas de clientes.
Verifique além disso os registos de autenticação. Em /var/log/auth.log (Debian, Ubuntu) ou /var/log/secure (família RHEL), o serviço SSH regista as autenticações bem-sucedidas com a impressão digital da chave usada. Assim vê se a chave estranha já foi usada e a partir de que endereço.
Pense também no sentido inverso. Se no servidor houver chaves privadas, por exemplo em ~/.ssh/id_* para deployments ou cópias de segurança, um atacante pode tê-las copiado. Com elas alcança talvez outros servidores, repositórios Git ou destinos de cópia de segurança. Tais chaves consideram-se esgotadas depois de uma intrusão: criar chaves novas e remover as antigas em todos os sistemas de destino.
Uma chave estranha raramente é o único vestígio. Quem a depositou tinha direitos de escrita e talvez tenha montado outros caminhos, como cronjobs ou contas adicionais. Verifique por isso também os cronjobs escondidos e as contas de administrador estranhas. Se o atacante teve direitos de root, uma reconstrução do servidor é muitas vezes mais fiável do que uma limpeza.
Só remova chaves estranhas quando o PHP estiver num estado corrigido (8.5.12, 8.4.27, 8.3.36, 8.2.35 ou backport confirmado) e todos os workers tiverem sido reiniciados. Caso contrário, o atacante pode voltar a inscrever a chave imediatamente através da mesma vulnerabilidade.
Reforçar depois o acesso SSH
Depois da limpeza, vale a pena um reforço rápido. A maioria dos pontos aplica-se depressa, mas deve ser sempre testada com uma segunda sessão aberta, para que não fique bloqueado.
| Medida | Definição ou procedimento |
|---|---|
| Autenticação apenas por chave | PasswordAuthentication no |
| Não permitir autenticação direta de root | PermitRootLogin no, trabalhar através de contas pessoais com sudo |
| Desativar o segundo ficheiro de chaves | AuthorizedKeysFile .ssh/authorized_keys |
| Limitar a chave à origem | opção from= antes da chave, por exemplo para servidores de cópia de segurança |
| Restringir chaves de serviço | opção restrict e command= fixo para automatização |
| Utilizador do servidor web sem login | shell de login nologin, sem .ssh no diretório pessoal |
Mantenha além disso uma lista de todas as chaves autorizadas com proprietário e finalidade. Quando um colaborador ou prestador sai, a sua chave é removida em todos os servidores. Sem esta lista, a próxima verificação volta a ser trabalho de detetive. Diretrizes de reforço reconhecidas para SSH constam também dos CIS Benchmarks.
Como ajuda concretamente a PHP SOS?
- Apuramos que ficheiros de chaves o seu serviço SSH realmente lê e verificamos cada entrada face aos proprietários conhecidos.
- Guardamos os achados e analisamos os registos de autenticação, para esclarecer se uma chave estranha foi usada.
- Limpamos chaves, contas e cronjobs pela ordem certa e fechamos antes a vulnerabilidade.
- No âmbito do hardening de servidores, aplicamos as definições SSH e configuramos uma gestão de chaves com lista de proprietários.
Perguntas frequentes
Como reconheço que uma chave SSH é estranha?
Cada chave tem uma impressão digital e, em geral, um comentário no fim da linha. Compare as impressões digitais com as chaves dos seus colaboradores e prestadores. O comentário por si só não prova nada, porque é de livre escolha e pode ser falsificado.
Ajuda alterar a palavra-passe de root?
Contra uma chave introduzida, não. A autenticação por chave não precisa de palavra-passe. Por isso, os próprios ficheiros authorized_keys têm de ser verificados e limpos.
Porque é que o utilizador do servidor web pode ter uma chave SSH?
O utilizador do servidor web tem um diretório pessoal próprio, no Debian e no Ubuntu muitas vezes /var/www. Se aí existir um .ssh/authorized_keys e a conta tiver uma shell de login, é possível autenticar-se como esse utilizador. Com um diretório web gravável, código PHP introduzido pode criar um ficheiro destes.
O que é authorized_keys2?
Um segundo ficheiro mais antigo que o OpenSSH também lê, segundo a configuração padrão. Muitos guias de verificação ignoram-no. Controle com sshd -T que ficheiros o seu servidor realmente avalia.