- Em um servidor Hetzner operado por um usuário, foi detectado um uso anormal de CPU e, após investigação, descobriu-se que um programa de mineração da criptomoeda Monero (
xmrig) estava em execução
- A causa foi o comprometimento do contêiner da ferramenta de analytics Umami, que incluía a vulnerabilidade de execução remota de código no Next.js (CVE-2025-66478)
- Felizmente, como esse contêiner era executado com um usuário não root (
non-root) e não tinha mount no host nem elevação de privilégios, a invasão ficou limitada ao interior do contêiner
- O invasor explorou a desserialização insegura dos componentes de servidor do Next.js para executar um payload malicioso e instalar o minerador
- Este caso mostra a importância do gerenciamento de dependências e das configurações de segurança de contêineres, e o autor reforçou as medidas de segurança com ativação de firewall, endurecimento do SSH e atualizações regulares
O hack e a resposta inicial
- Recebeu da Hetzner um e-mail de alerta informando que o servidor havia escaneado a rede externa
- Incluía o aviso de que o servidor poderia ser bloqueado caso não houvesse ação em até 4 horas
- Após acessar por SSH e verificar, encontrou-se um processo usando 819% de CPU no caminho
/tmp/.XIN-unix/javae, além de vários processos xmrig
- Foi confirmado que a mineração de criptomoeda havia ocorrido por cerca de 10 dias
Investigação da via de invasão
- Todos os processos maliciosos estavam em execução com o usuário UID 1001, o que correspondia ao contêiner do Umami
- Foi encontrado um executável do minerador no diretório
/app/node_modules/next/dist/server/lib/xmrig-6.24.0/
- O comando de execução incluía o endereço do pool de mineração
auto.c3pool.org:443 e a chave do usuário
Vulnerabilidade no Next.js e forma do ataque
- A causa foi a vulnerabilidade de desserialização dos React Server Components do Next.js (CVE-2025-66478)
- Quando o invasor envia uma requisição HTTP manipulada, código arbitrário pode ser executado no servidor
- Como resultado, torna-se possível instalar e executar um minerador de criptomoeda
- O autor achava que “não usava Next.js diretamente”, mas só depois percebeu que o Umami é baseado em Next.js
Verificação do isolamento do contêiner
- Foi confirmado que
/tmp/.XIN-unix/javae não existia no sistema de arquivos do host
- Era apenas o efeito de os processos do contêiner aparecerem na saída do
docker ps, enquanto o isolamento real era mantido
- Resultado do
docker inspect
- Usuário:
nextjs
Privileged: false
Mounts: nenhum
- Portanto, o malware não conseguiu acessar o host, registrar tarefas no cron, criar serviços do sistema nem instalar rootkits
Recuperação e reforço de segurança
- Após parar e excluir o contêiner infectado do Umami, o uso de CPU voltou ao normal
- O firewall UFW foi ativado, permitindo apenas SSH, HTTP e HTTPS
- Depois de reportar os resultados da investigação à Hetzner, o ticket foi encerrado em 1 hora
Lições e pontos de melhoria
- Dizer “eu não uso X” não inclui necessariamente as dependências
- É preciso verificar de qual stack tecnológica são compostas as ferramentas utilizadas
- Ficou comprovado o efeito do isolamento de contêineres
- Uso de usuário não root, modo sem privilégios e ausência de volumes desnecessários impediram a ampliação dos danos
- Há necessidade de defesa em profundidade (Defense in Depth)
- Firewall, fail2ban, monitoramento e atualizações regulares são essenciais
- Também foi destacada a importância de escrever o próprio Dockerfile e de minimizar os privilégios do contêiner
Medidas após o incidente
- O Umami foi reimplantado na versão mais recente e todos os contêineres de terceiros foram auditados
- Foram verificados usuário de execução, mounts, momento de atualização e necessidade de cada um
- Houve migração para autenticação por chave SSH, desativação do login por senha e configuração do fail2ban
- Foi feito reforço do monitoramento com Grafana e Node Exporter, além da aplicação imediata de atualizações de segurança
Conclusão
- A vulnerabilidade no Next.js do Umami permitiu o abuso do servidor para minerar Monero por 10 dias, mas
o isolamento do contêiner e a execução sem root limitaram os danos
- Com essa experiência, o autor assimilou a importância de entender as dependências, configurar a segurança e gerenciar atualizações
- O incidente foi resolvido em cerca de 2 horas e ficou como um caso real que comprovou a eficácia da segurança de contêineres
1 comentários
Comentários do Hacker News
Antigamente eu recomendava ativar o UFW, mas hoje recomendo o firewalld
O UFW fica difícil de administrar com o tempo, enquanto o firewalld é bem mais estável por usar configuração baseada em XML
Com o comando
firewall-cmd, dá para configurar SSH, HTTPS, porta 80 etc., e é melhor usar o backend nftablesNo caso do Docker, ele frequentemente contorna as regras do firewall e abre portas por conta própria, então é mais seguro definir
StrictForwardPorts=yesem/etc/firewalld/firewalld.conf8080:8080, é melhor vincular ao IP privado, como192.168.0.1:8080:8080Eu rodo Docker numa VM 10.0.10.11 e achei prático deixar o acesso disponível só via WireGuard, com o Caddy fazendo reverse proxy
Malware vai tentar se conectar a pools de mineração externas ou servidores de C2, então é preciso bloquear o acesso à rede para binários não autorizados
Também ajuda remover permissão de execução de
/tmp,/var/tmpe/dev/shmnftables.confjá é simples e claro o suficienteO iptables já está obsoleto, então não é obrigatório ter uma camada extra como o firewalld
Isso parece ser um problema relacionado ao “React2Shell CVE-2025-55182”
É estranho que uma vulnerabilidade que afetou sistemas por mais de um ano quase não tenha recebido atenção
Se você implantou um webapp com Next.js nos últimos 12 meses, há uma boa chance de ele já fazer parte de uma botnet
É frustrante ver a indústria ficando só em conselhos do tipo “use Docker” e “ative o firewall”
Ultimamente tenho ficado tão cético com o ecossistema de frontend que estou pensando em migrar minha carreira para C++
Agora a combinação de Next.js, React, Tailwind e Postgres está praticamente consolidada como padrão há 5 anos
Comparado ao período de proliferação de frameworks no fim dos anos 2000 e início dos 2010, está bem mais estável
Se você não gosta de modas e mudanças, o desenvolvimento com IA muda muito mais rápido hoje
No backend, use uma stack sólida como .NET, Java ou Go, e no frontend escolha o que preferir
Isso reduz CVEs e também o cansaço com tecnologia
Discussão relacionada no GitHub
Se você limitar o uso de CPU de um contêiner Docker com
--cpus="0.5", um serviço com defeito ou minerador não afeta o sistema inteiroOperar um servidor sem firewall é uma escolha bem ousada
Se você usar também o firewall externo da Hetzner, ganha mais uma camada de defesa para quando cometer algum erro
Eu permito SSH só a partir do IP da minha casa e, quando preciso de acesso externo, abro temporariamente pelo site da Hetzner
O que realmente importa é não rodar software com vulnerabilidade de RCE
O Docker parecer um salvador, na prática, foi mais sorte do que qualquer outra coisa
Em vez disso, dá para usar um bastion host e controlar entrada e saída com um proxy HTTP, mas a configuração é complexa
Usar portas não padrão teve um efeito surpreendentemente útil
Não sei se funciona de verdade, mas parece uma espécie de guarda-chuva psicológico
Fiquei curioso se rodar um contêiner Docker como root permite atacar o host também
Se você quer rodar código não confiável, precisa usar VM (KVM/QEMU) ou tecnologias como gVisor(https://gvisor.dev/) e Firecracker(https://firecracker-microvm.github.io/)
É melhor entender o Docker não como sandbox, mas como um ambiente de execução isolado
A configuração padrão do Docker não limita RAM, CPU nem uso de disco, então ele também é vulnerável a ataques de DoS
Além disso, muitos guias recomendam opções perigosas como
--privilegedouCAP_SYS_PTRACETambém é possível subir um novo contêiner e escalar para privilégios de root
Como isso ainda não é o padrão no Docker, se você não configurar, o risco de escape é grande
No passado, a maioria dos escapes de contêiner poderia ter sido evitada com user namespace
Se o servidor não lida com dados sensíveis, limpar apenas os contêineres pode ser suficiente
Para reduzir a superfície de ataque, serviços que não precisam ser públicos não devem ser expostos externamente
Por exemplo, ferramentas de análise podem ficar acessíveis só via WireGuard ou proxy SOCKS por SSH
Eu também sofri uma infecção por minerador de Monero num servidor da Hetzner
Felizmente aconteceu só dentro de um contêiner LXC do Incus, e como a prioridade de CPU era baixa eu nem percebi
Uma chave SSH foi adicionada à conta root e um agente de administração remota foi instalado
No fim descartei o contêiner, mas tirei algumas lições disso
O texto incluía alucinações de IA que não tinham sido revisadas por uma pessoa
Ele repetia que era uma vulnerabilidade relacionada ao Puppeteer, mas isso não era verdade
Recentemente estão instalando mineradores de Monero por toda parte explorando uma vulnerabilidade do React 19
Eu também passei pelo mesmo problema
Funciona como uma espécie de bug bounty automático, no sentido de revelar a vulnerabilidade
Se você tem bom monitoramento de rede ou processos, é fácil detectar
Acabou sendo uma boa oportunidade para melhorar o sistema de backup
Quando vejo casos assim, penso que foi melhor eu não continuar administrando VPS por conta própria
Já tentei antes, mas me considero só um administrador mediano e achei difícil manter a segurança
Então hoje prefiro pagar e deixar isso com especialistas, o que me dá muito mais tranquilidade