Saltar para o conteúdo
Ataque à cadeia de fornecimento BdThemes através de JSON contaminado
Beatriz Tavares
Beatriz Tavares 9 dEurope/Budapest August dEurope/Budapest 2026 · 11 min de leitura

Ataque à cadeia de fornecimento BdThemes através de JSON contaminado

Uma cadeia de fornecimento comprometida no ecossistema BdThemes permitiu executar JavaScript malicioso nas sessões autenticadas de administradores do WordPress. O ataque está a explorar respostas JSON remotas destinadas a banners promocionais, sem alterar qualquer ficheiro do plugin no repositório oficial ou no disco do site; por isso, pode não detetar-se com verificações de integridade baseadas em ficheiros.

Os sete plugins afetados estão temporariamente fechados no diretório de plugins do WordPress enquanto decorre a inspeção. Se tens algum instalado, trata o incidente como uma potencial comprometimento completo do site: o código está a criar administradores indevidos, a instalar uma webshell e a estabelecer persistência no servidor.

Risco imediato

A versão vulnerável do componente não tem correção indicada. Os endpoints remotos passaram a devolver JSON limpo em 8 de agosto de 2026, mas isso não remove contas, plugins, ficheiros MU nem opções da base de dados que já tenham sido criados.

Como funciona a cadeia de ataque

Os plugins BdThemes incluem o Biggopti, um componente interno que está a obter banners promocionais de uma API e a mostrá-los no painel de administração. A API serve ficheiros JSON estáticos a partir de um bucket DigitalOcean Spaces protegido por Cloudflare, não de um servidor de aplicações dinâmico; o acesso de escrita ao bucket foi comprometido e as respostas legítimas foram substituídas por registos preparados para explorar XSS.

O script do Biggopti é colocado em fila durante admin_init, pelo que está a correr em todos os carregamentos de páginas wp-admin para cada plugin que o usa. Ao construir o contentor HTML no DOM, o valor remoto display_id concatena-se diretamente no atributo id, sem escape no lado do cliente; o campo data-display-id do mesmo código é escapado, o que confirma que a falha se limita à injeção do atributo id.

// display_id vem da resposta JSON remota e não é escapado
var f = t.display_id || t.id || "default";
var m = "bdt-admin-biggopti-api-biggopti-" + f;
A = 'id="' + m + '"'; // valor injetado no DOM

// Noutro atributo, o código já escapava caracteres HTML
function escapeAttribute(value) {
  return (value || "")
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

A injeção de display_id está a sair do atributo id e a acrescentar um handler onanimationstart. Uma animação CSS dispara-o em cerca de 10 milissegundos, silenciosamente, assim que um administrador abre qualquer página do painel. Embora versões posteriores tenham acrescentado um sanitizador com DOMParser para o campo de conteúdo do banner, removendo tags e handlers perigosos, o atributo id continuou sem escape.

A falha foi introduzida em 1 de março de 2026, no Prime Slider 4.1.9, e acabou por aplicar-se a outros plugins. Não é necessária uma atualização do plugin para o site ficar exposto: basta que um administrador esteja a carregar o painel enquanto a resposta JSON maliciosa está disponível. A execução está a acontecer no navegador autenticado, o que dá ao script os nonces e as permissões dessa sessão.

Plugins e vulnerabilidade afetados

A vulnerabilidade é uma XSS através do parâmetro display_id da API Sigmative na biblioteca Biggopti, classificada com CVSS 5,4, de gravidade média e sem correção. Um atacante que controle o servidor da API consegue injetar scripts arbitrários nas páginas que mostram o registo contaminado; no cenário observado, está a visar especificamente administradores autenticados.

Payloads observados e impacto

O handler injetado está a descarregar scripts externos conforme o endpoint utilizado pelo plugin. O payload principal, w2.js, é servido aos plugins que usam api-data-all-records; o alternativo, x.js, surge alojado diretamente na infraestrutura BdThemes para vítimas que usam api-data-records. Ambos procuram criar acesso administrativo persistente e comunicar os resultados a uma infraestrutura de comando e controlo (C2).

Payload principal: w2.js

  1. Validação do C2: contacta ia-cdn[.]com/fz/c, enviando a origem do site para receber instruções de seleção. O script termina se o C2 responder com o estado skip ou done.
  2. Criação de administrador indevido: usa o X-WP-Nonce presente na sessão administrativa para criar um administrador através da REST API do WordPress. Se falhar, recorre a submissões de formulários normais.
  3. Instalação de webshell: descarrega do C2 um ZIP que se faz passar por plugin e instala-o pelo formulário padrão de carregamento de plugins. Usa o slug wp-smart-thumbnails, ou outro nome neutro semelhante, e contém a webshell emer-run.php, chamada diretamente por URL.
  4. Persistência em MU-plugins: ao chamar emer-run.php, instala dois módulos na diretoria de plugins obrigatórios. As amostras observadas tinham datas retroativas para setembro de 2025, procurando misturar-se com timestamps legítimos; os nomes dos ficheiros podem variar entre infeções.
  5. Backdoor de magic login: o primeiro módulo permite entrar como administrador sem autenticação através de ?_wplogin=<token> e visa o administrador registado há mais tempo no site.
  6. Ocultação anti-análise: o segundo módulo usa hooks nas queries da base de dados do WordPress para esconder as contas indevidas da lista administrativa de utilizadores e reduzir os totais de utilizadores em conformidade.
  7. Exfiltração: envia os resultados de cada fase para o C2 através de navigator.sendBeacon.

Payload alternativo: x.js

O x.js está a calcular credenciais administrativas determinísticas a partir do hostname da vítima. Calcula um hash inteiro do hostname, converte o valor absoluto para base 36 e usa os primeiros seis caracteres: o utilizador segue o padrão bd_ seguido desse hash e a palavra-passe segue Bd@26! mais o hash e o sufixo x. A conta associa-se a um endereço com domínio @wordpress.org.

// Lógica defensivamente reproduzida para identificar o padrão de credenciais
function makeCreds(host) {
  let hash = 0;
  for (let i = 0; i < host.length; i++) {
    hash = ((hash << 5) - hash + host.charCodeAt(i)) | 0;
  }
  const suffix = Math.abs(hash).toString(36).slice(0, 6);
  return {
    user: 'bd_' + suffix,
    pass: 'Bd@26!' + suffix + 'x'
  };
}

Como as credenciais são previsíveis, os atacantes não precisam de manter uma lista central de sites comprometidos: podem calculá-las quando conhecem o domínio. O script está a criar a conta pela página /wp-admin/user-new.php, extrai o nonce da página, usa a função de logout encontrada no HTML e guarda uma flag em localStorage quando consegue concluir a tentativa. Depois está a enviar para o C2 o estado, o utilizador, a palavra-passe, a origem, o URL de logout e o URL da página, recorrendo a sendBeacon ou a fetch com keepalive como alternativa.

Indicadores de comprometimento

A investigação deve cruzar os indicadores de rede, sistema de ficheiros e base de dados. Os endpoints Sigmative contaminados estão a devolver JSON limpo, mas os artefactos que o payload instalou podem continuar presentes e devem procurar-se ativamente.

Recursos externos

  • Payload principal: ia-cdn[.]com/fz/w2.js
  • Endpoint de beacon C2: ia-cdn[.]com/fz/c
  • Endpoint contaminado, já limpo: api[.]sigmative[.]io/prod/store/api/biggopti/api-data-all-records
  • Endpoint contaminado, já limpo: api[.]sigmative[.]io/prod/store/api/biggopti/api-data-records
  • Payload alternativo, já limpo: api[.]sigmative[.]io/prod/store/api/biggopti/x.js

Ficheiros e opções da base de dados

  • Webshell emer-run.php, MD5 1024732009983dd5e54b4cf5593f04d4.
  • Backdoor MU class-wp-token-validate.php, MD5 7719cd98a35ffad2771f26d1ceab7d27.
  • Módulo furtivo MU class-wp-query-9d127ff3.php, ou nome semelhante no padrão class-wp-query-*.php, MD5 9aadc3e5c5242b273bd17c5bdc358845.
  • Módulo MU apresentado como verificação de saúde, wp-cache-optimizer.php, MD5 e450ae5bc4bfc0d960dded06a76bb8e9.
  • Opção fz_emer_login_tokens, onde se guardam tokens de magic login.
  • Opção fz_emer_done_v1, que assinala a conclusão do comprometimento.
  • Contas com endereços @wordpress.org ou @developer.wordpress.org.
  • Nomes de utilizador que correspondam a bd_ mais seis caracteres alfanuméricos.

Cronologia do incidente

  • 1 de março de 2026: o JavaScript da API Biggopti entra no Prime Slider 4.1.9, no SVN r3471891. O display_id fica sem escape no atributo id e o endpoint usado é api-data-records.
  • 10 de maio de 2026: o endpoint muda para api-data-all-records. Adiciona-se um sanitizador DOMParser ao campo de conteúdo, mas o atributo id continua vulnerável.
  • 23 de junho de 2026: data start_date da campanha contaminada, num aviso “Summer Sale”; é a data mais antiga em que a XSS pode ter estado ativa.
  • 6 de agosto de 2026, 22:40 UTC: último Last-Modified observado em api-data-records contaminado.
  • 7 de agosto de 2026, 09:11 UTC: último Last-Modified observado em api-data-all-records contaminado.
  • 7 de agosto de 2026: o ataque é observado em ambiente real e os plugins são fechados no diretório do WordPress enquanto aguardam revisão.
  • 7 de agosto de 2026, 16:56 UTC: são recolhidos artefactos da investigação.
  • 8 de agosto de 2026: ambos os endpoints da API passam a devolver JSON limpo.

O que deves verificar e fazer agora

Desativa os plugins afetados e impede novos carregamentos do painel por utilizadores não estritamente necessários enquanto estiveres a analisar o ambiente. A limpeza está a exigir mais do que reinstalar plugins, porque a cadeia deixa alterações na base de dados, em contas de utilizadores e na diretoria de MU-plugins; verifica também os registos HTTP e DNS para ligações aos indicadores externos.

  1. Audita manualmente a lista de utilizadores, incluindo diretamente na base de dados, para encontrar administradores bd_ com seis caracteres, contas com os domínios indicados e contas inesperadas que a interface possa ocultar.
  2. Inspeciona wp-content/mu-plugins/, as diretorias de plugins e os ficheiros acessíveis por URL para os nomes, padrões e hashes indicados. Remove os artefactos indevidos apenas depois de preservar evidência e de garantir que tens uma cópia de segurança.
  3. Consulta a tabela de opções para fz_emer_login_tokens e fz_emer_done_v1, bem como outros dados inesperados relacionados com o incidente.
  4. Revoga sessões, nonces e palavras-passe potencialmente expostos; redefine as credenciais de todos os administradores e substitui as chaves e salts do WordPress para invalidar cookies autenticados.
  5. Roda uma análise de malware que cubra o sistema de ficheiros, a base de dados e os indicadores de rede. Uma verificação que compare apenas ficheiros dos plugins pode não encontrar esta infeção.
  6. Revê as credenciais e os controlos de acesso da infraestrutura associada aos plugins se gerires uma instalação BdThemes, porque o incidente indica comprometimento grave de credenciais de armazenamento cloud ou da infraestrutura interna.

Esta campanha está a demonstrar que um feed remoto aparentemente inofensivo pode tornar-se um vetor de execução remota quando o código de apresentação confia nos dados recebidos. Depois de eliminar os indicadores, mantém a monitorização de contas administrativas, pedidos a endpoints suspeitos e alterações em MU-plugins, pois é essa persistência que pode devolver o controlo do site ao atacante.

Cobertura de deteção

As assinaturas de malware e regras de WAF para este comprometimento foram disponibilizadas em 7 de agosto de 2026 aos utilizadores Wordfence Premium, Care e Response e a clientes pagos do Wordfence CLI. As edições gratuitas do Wordfence e Wordfence CLI recebem-nas após o atraso habitual de 30 dias.

Junte-se à comunidade HelloWP!

Converse conosco sobre WordPress, desenvolvimento web e compartilhe experiências com outros desenvolvedores.

- membros
- online
Participar

Usamos cookies para melhorar a sua experiência. Ao continuar, concorda com a nossa Política de Cookies.