A lista de portas abertas é a lista de caminhos até ao seu servidor. Tudo o resto — firewall, WAF, deteção de intrusões — constrói-se por cima. Por isso «o que está à escuta aqui» vem em primeiro lugar em qualquer auditoria, e é também a verificação que mais vezes dá um resultado desagradável: metade do que aparece não foi aberta por si mas pelo instalador de algum pacote.

Ler a saída

sudo ss -tulpn

As opções: t para TCP, u para UDP, l só o que escuta, p o processo, n para os números continuarem números. Sem sudo a coluna do processo fica vazia e o exercício perde sentido.

O que importa é a coluna Local Address:Port, e a diferença ali é essencial:

  • 127.0.0.1:3306: o serviço só é alcançável a partir da própria máquina. Isso é bom;
  • 0.0.0.0:3306: a partir de qualquer endereço IPv4, ou seja, da internet. É isso que há que verificar;
  • [::]:3306: o mesmo para IPv6. Uma linha à parte, e passa despercebida com regularidade;
  • 203.0.113.25:443: num endereço concreto, normalmente de propósito.

Depois, para cada linha com 0.0.0.0 ou [::], faça uma pergunta: deve um estranho conseguir chegar aqui? Para 80 e 443 a resposta é sim. Para quase tudo o resto, não.

Os achados habituais

Redis, porta 6379. A linha mais perigosa que existe. Por omissão o Redis não exige palavra-passe, e os seus comandos permitem escrever um ficheiro no disco, ou seja, uma chave alheia no authorized_keys. Entre o Redis aparecer num endereço público e ser aproveitado passam horas, por vezes menos. Verifique bind 127.0.0.1 e protected-mode yes na configuração.

Memcached, 11211/UDP. Mesmo que lá dentro não haja nada de valioso, o seu servidor torna-se amplificador de ataques alheios, e a reclamação virá do alojamento.

MySQL e PostgreSQL, 3306 e 5432. Há palavra-passe, mas tenta-se contra ela sem parar, e as versões das bases de dados são atualizadas menos vezes do que seria desejável. Quase nunca precisam de estar expostas: a aplicação vive na mesma máquina, e para o seu trabalho basta um túnel SSH.

Elasticsearch 9200, MongoDB 27017. Historicamente sem autenticação por omissão. As instâncias públicas destes serviços são fonte constante de notícias sobre fugas de dados.

A API do Docker, 2375. Uma porta de comando do Docker aberta é root no anfitrião sem palavra-passe nenhuma. Costuma aparecer depois de experiências com acesso remoto ao Docker.

Painéis de gestão e phpMyAdmin nas suas portas: 8080, 8083, 10000. Não é que nunca se devam abrir, mas são eles que concentram o grosso das tentativas.

Corrigir no serviço, não na firewall

A vontade de fechar cada achado com uma regra do UFW compreende-se, mas essa é a segunda linha, não a primeira. Uma regra pode ser apagada por engano, uma firewall desligada por momentos durante uma depuração, e o Docker publica portas contornando o UFW por completo. Uma definição de associação na configuração do serviço sobrevive a tudo isso:

  • MySQL/MariaDB: bind-address = 127.0.0.1;
  • PostgreSQL: listen_addresses = 'localhost';
  • Redis: bind 127.0.0.1 ::1;
  • Docker Compose: publicação como "127.0.0.1:5432:5432".

A firewall põe-se por cima como seguro, não em vez disto.

Encontrar o processo quando não é claro

O ss dá o nome e o pid. Depois:

sudo systemctl status <pid>
sudo lsof -i :8080

O primeiro comando nomeia a unidade systemd a que o processo pertence, e isso costuma bastar para perceber o que é e se faz falta. Um processo desconhecido à escuta numa porta alta e iniciado fora das pastas do sistema — de /tmp ou /dev/shm, por exemplo — já não é questão de configuração mas motivo para uma investigação própria.

A verificação a partir de fora é obrigatória

O ss responde a «o que está à escuta», não a «a que se consegue chegar». Entre as duas coisas estão a firewall, o NAT e as regras do alojamento. A única resposta honesta vem de um varrimento a partir de outra máquina:

nmap -Pn -p- 203.0.113.25
nmap -Pn -p- -6 2001:db8::1

Não deixe de lado o segundo comando: quase todo o VPS tem endereço IPv6, as suas regras escrevem-se à parte, e o serviço escuta em ambas as versões do protocolo ao mesmo tempo.

Não é uma verificação pontual

A lista de portas abertas muda sozinha. Instalou um pacote e ele trouxe um serviço que abriu uma porta. Atualizou um painel e ele repôs um valor por omissão. Iniciou um contentor e ele publicou uma porta contornando a firewall. Uma verificação pontual responde pelo dia de hoje e por mais nada.

O valor não está na lista em si mas nas suas mudanças: uma porta nova que ontem não existia é um sinal curto e muito elucidativo. É assim que vale a pena olhar para ela: como instantâneo com histórico, e não como saída do ss reconstruída de memória. A página de demonstração abaixo mostra exatamente isso.