Como um ataque de envenenamento de script pode visar simultaneamente dados do usuário e fundos de transferência?Autor do artigo, fonte: SlowMist Tech
Contexto
Recentemente, membros da equipe de segurança da SlowMist, durante a análise rotineira de inteligência de ameaças, monitoraram uma atividade de ataque envolvendo a contaminação de scripts relacionados ao sistema de atendimento ao cliente Udesk. A equipe posteriormente obteve duas amostras JavaScript: udeskApi.2026-10-16.cached.js e deeps.js, e realizou uma análise para rastrear como o código malicioso se infiltrava nas páginas por meio dos scripts de atendimento ao cliente e para identificar o que ele fazia com os dados dos usuários e as operações comerciais.
A inspeção da amostra revelou gradualmente dois tipos de riscos: um script malicioso coleta simultaneamente dados de sessão e informações sensíveis enviadas pelos usuários na página, enquanto modifica endereços de recarga e copia conteúdo de acordo com as regras do site. O primeiro pode permitir que atacantes se passem por sessões de login ou assumam contas, enquanto o segundo pode levar os usuários a transferirem fundos de recarga para endereços de recebimento substituídos. A partir da entrada de carregamento do script de atendimento ao cliente, seguimos a lógica de leitura de dados, envio de rede e modificação de página para recriar a implementação e as condições de gatilho desses dois tipos de comportamento.
MistEye resposta
MistEye é um sistema de inteligência de ameaças e monitoramento de segurança dinâmico para Web3, desenvolvido independentemente pela SlowMist, que integra capacidades de monitoramento de segurança e agregação de inteligência para fornecer alertas de risco em tempo real e proteção de ativos aos usuários.
MistEye já sincronizou o risco por meio de alertas de inteligência e canais de notificação aos clientes.

Carregador malicioso e mecanismo de carregamento de carga remota
Ao abrir o arquivo udeskApi.2026-10-16.cached.js, é possível ver o código para funcionalidades como botão de atendimento ao cliente, iframe de bate-papo, rastreamento de visitantes e comunicação de mensagens. Ao continuar verificando o final do arquivo, após o término da estrutura principal, há uma função independente: ela decodifica duas strings por meio de _ud(), cria elementos e os insere no head do documento atual.
Este trecho não menciona diretamente o nome da tag nem a URL remota. Se for feita apenas uma busca pelo nome de domínio em texto simples, o ponto de carregamento pode ser facilmente ignorado. Ao analisar a implementação de _ud(), descobrimos que ela pega dois caracteres hexadecimais por vez e os converte em caracteres; após expandir as constantes, o destino de carregamento torna-se claro.
736372697074 decodificado como script, outro constante decodificado como https[:]//udeskqlobal[.]com/deeps.js. O domínio, com qlobal iniciado pela letra q, deve manter essa grafia durante a pesquisa. O carregador define o script como assíncrono e depois o insere na página; quando a execução atinge esse ponto e as políticas do navegador e a rede permitem, o código remoto pode ser inserido no documento atual.
A carga correspondente a esse URL é deeps.js. O foco da investigação passou do SDK de atendimento ao cliente para a carga em si. Scripts clássicos de terceiros são executados no contexto do documento incorporado e os dados aos quais podem acessar dependem da página ou iframe em que estão sendo executados. A janela de bate-papo de atendimento ao cliente usa um iframe e não isola automaticamente os scripts carregados na página hospedeira.
Mecanismo de coleta de dados da web e escopo de impacto
O deeps.js primeiro lê window.location.hostname e gera a configuração C conforme as regras dos três sites. Para determinar quais páginas serão coletadas, essa configuração sozinha não é suficiente: é necessário rastrear o local de verificação de saída para saber se ela restringe todo o script ou apenas algum módulo.
Ao seguir o fluxo de controle, observamos que a leitura de cookies e armazenamento da web, o envio de instantâneo de inicialização e os ganchos de formulário e autenticação aparecem todos antes de if (!C) return;. Abaixo, extraímos as instruções de envio de instantâneo e o gancho XHR final na ordem do código-fonte; os comentários indicam o código omitido entre eles, correspondendo à visualização formatada D:L100, D:L151–L166.
A localização da decisão de saída esclarece o escopo do impacto: mesmo que o hostname não corresponda às três regras de sites, o script entrará primeiro no caminho de coleta de dados e instalará os ganchos, antes de sair do módulo de endereço. Ao investigar páginas expostas, não se deve buscar apenas nas configurações desses três sites.
Ao ser iniciado, a carga útil lê cookies, localStorage e sessionStorage acessíveis na página atual. Esses locais podem armazenar estado de login, perfil do usuário e dados de negócios; se contiverem tokens de login ainda válidos e reutilizáveis, um atacante que os obtiver poderá se passar pela sessão do usuário. O script também inclui a URL da página principal e a origem do documento atual, enviando esses dados juntamente com a página de origem.
O processo de coleta é tolerante a erros item a item. Quando a leitura da URL principal entre origens falha, o script substitui por x e continua processando outros campos; os dois tipos de armazenamento de páginas são serializados em JSON. O escopo dos cookies é limitado ao conteúdo legível por document.cookie, e cookies HttpOnly não estão incluídos.
O script também mantém entradas para os dados enviados posteriormente. Quando o usuário envia o formulário, ele percorre os elementos input, select e textarea, copiando o conteúdo não vazio e continuando o processo de envio original. Campos preenchidos na página, como nome de usuário, senha e código de verificação, podem ser encaminhados por caminhos de envio adicionais, e sua exposição pode ser usada para acessar ou assumir o controle da conta.
Este caminho implementa a substituição de HTMLFormElement.prototype.submit e a escuta de eventos de submit na fase de captura. Para páginas que enviam dados diretamente por meio de interfaces, o script também envolve fetch e XHR: quando a requisição possui corpo e a URL contém palavras-chave como login|signin|auth|register|signup|password, o conteúdo correspondente é copiado e a chamada original da requisição é mantida. No ramo fetch, exige-se adicionalmente que a URL seja uma string e o corpo venha das opções da requisição; quando objetos como FormData são serializados diretamente em JSON, o conteúdo coletado pode estar faltando campos reais.
Mecanismo de vazamento de dados e canal de backup
A entrada de coleta acima chama finalmente o mesmo _send(). Ao rastrear essa função, é possível ver que o endpoint fixo é https[:]//udeskqlobal[.]com/c.php. A captura inicial usa os campos s, o, c, l, ss para transportar respectivamente o endereço da página, a fonte atual, o cookie legível e dois tipos de armazenamento web; formulários e solicitações de autenticação subsequentes são enviados ao serem acionados.
A função extrai os parâmetros após o ponto de interrogação na URL e os insere no corpo do POST assíncrono, definindo Content-Type: application/x-www-form-urlencoded. Abaixo, mantém-se integralmente a função de envio (D:L45–L60):

O caminho de envio também inclui um fallback de solicitação de imagem: quando ocorre um erro XHR ou uma anomalia síncrona durante o envio, o script cria um objeto Image, atribui a URL com parâmetros à propriedade src e tenta enviar novamente os dados por meio de GET. A URL é truncada nos primeiros 8.000 caracteres JavaScript; conteúdos mais longos podem estar incompletos.
Ao interpretar esse caminho, é necessário distinguir entre "envio da requisição" e "leitura da resposta". O script não lê a resposta de c.php; uma POST cross-origin que atenda às condições de requisição simples pode ser enviada primeiro, com a leitura da resposta limitada pelo navegador, portanto, erros CORS podem ocorrer simultaneamente ao envio da requisição. Os registros de investigação devem verificar simultaneamente o corpo da POST e os parâmetros GET da imagem, enquanto as políticas de saída devem verificar separadamente connect-src e img-src. Um formulário comum que desencadeie navegação de documento também pode afetar a conclusão de requisições assíncronas.
Até aqui, o destino dos dados da sessão da página e do conteúdo submetido posteriormente ficou claro. No entanto, após a verificação de saída do site, a carga útil ainda mantém outro conjunto de operações: identificação do formato de endereço, modificação do texto da página e assumir o controle do caminho de cópia. Esses códigos direcionam a investigação ainda mais para o negócio de depósito.
Substituição de endereço de depósito e mecanismo de sequestro de área de transferência
Após if (!C) return;, o script entra no módulo de endereço. As três regras de hostname no início agora têm um propósito claro: corresponder a mgbx[.]com, bikingex[.] e bitxex[.]io, selecionando os seletores de elementos para endereço e botão de cópia em páginas diferentes.
Essas expressões regulares não possuem âncoras de início e fim, resultando em uma correspondência mais ampla do que a comparação exata de nomes de domínio. As regras da página também verificam o location.href completo, e parâmetros de consulta ou fragmentos contendo palavras-chave como deposit, recharge, assets também são considerados na avaliação. Após a correspondência com a página, elemento ou formato de endereço, o script escaneia a cada 200 milissegundos, substituindo os endereços de recarga identificados pelo valor configurado. Se o usuário realizar uma transferência válida usando o endereço substituído, o destinatário final será esse endereço.
Três filiais de站点 compartilham seis valores de configuração, marcados no código como BTC, EVM, TRON, Solana, LTC e DOGE. A identificação de endereços baseia-se apenas na forma dos caracteres e na ordem de correspondência, sem verificar a rede ou o checksum selecionados pelo usuário, podendo também identificar incorretamente identificadores de negócios comuns.
Continue verificando o código copiado; é possível observar que a amostra interfere simultaneamente na exibição da página e no conteúdo da área de transferência. Assim, mesmo que o usuário compare o endereço da página com o resultado copiado, poderá obter valores manipulados consistentes. As três rotas são:
- Empacotar a API do clipboard. navigator.clipboard.writeText chama primeiro R() para substituir os parâmetros, depois passa para o método original. Este caminho está restrito apenas pela configuração de hostname, não verifica novamente as condições da página de recarga e não depende da varredura DOM para elementos já atingidos.
- Substitua o botão de cópia. O script clona o botão correspondente, instala um novo ouvinte de clique e substitui o nó original. O novo ouvinte impede a ação padrão e a propagação do evento, tentando copiar o endereço armazenado na variável compartilhada _cur.
- Interceptar o evento copy. Quando _cur não estiver vazio e a regra da página for atendida, o ouvinte no documento substitui o conteúdo copiado por _cur, sem verificar se o texto selecionado pelo usuário é um endereço.
Entre eles, a API de área de transferência e o ouvinte de cópia estão adjacentes no código-fonte (D:L260–L275), mas possuem condições de gatilho diferentes:
_cur salva o último endereço substituído real. Quando vários endereços estiverem visíveis na mesma tela, a substituição mais recente sobrescreverá a gravação anterior, e vários botões podem copiar o mesmo valor. Se o endereço de configuração já estiver exibido ao carregar a página, a varredura não inicializará _cur, e os novos ouvintes de botão não escreverão conteúdo; os atributos de eventos embutidos HTML mantidos por clonagem ainda poderão participar do processamento de eventos.
Durante a análise, foi identificado um defeito de implementação que afeta a avaliação do comportamento: o script tenta ler o descritor de propriedade própria de textContent a partir de Element.prototype, enquanto a definição padrão da propriedade está em Node.prototype. Sob a relação de protótipo padrão, a tentativa subsequente de acessar .set lançará uma exceção. Após a falha desse ramo, o catch ignora a exceção; ao examinar o código anterior e posterior, verifica-se que a sondagem já foi registrada e os ganchos de cópia subsequentes ainda serão instalados conforme suas respectivas condições. Um único ramo com erro não interrompeu o módulo de sequestro de endereço.
Resumo
Após rastrear o carregador na parte final do script do suporte, identificamos o alvo do ataque: coletar dados utilizáveis para sequestrar sessões ou fazer login em contas, além de alterar os endereços de recebimento nas páginas de depósito e nas operações de cópia para os valores configurados. O primeiro não está sujeito às restrições de configuração dos três sites, enquanto o segundo é ativado por site e caminho de cópia específico, exigindo análise abrangente de diferentes cenários expostos.
As empresas que ainda estão carregando scripts relacionados devem interromper imediatamente a distribuição, remediar as credenciais expostas e verificar os objetivos de recarga por meio de backends confiáveis e registros de transações.
Sugestão
- Segure e interrompa a distribuição de recursos contaminados. Se a produção ainda estiver carregando scripts relacionados, interrompa o mais rápido possível após salvar a resposta real, a cadeia de solicitação, as informações de cache e o horário de coleta; restaure a partir de uma versão confiável verificada independentemente e verifique as configurações de hospedagem do site, CDN, construção e gerenciamento de tags.
- Buscar carregamento e registros de exfiltração. Consulta conjunta para domínios maliciosos, dois caminhos e hashes de arquivos; os registros de exfiltração verificam simultaneamente o corpo POST e parâmetros GET. Ao investigar scripts compactados, também buscar URLs hexadecimais no carregador, evitando apenas a detecção em texto plano.
- Encerre o documento contaminado e descarte as credenciais expostas. Feche completamente as páginas ou documentos WebView relacionados, evitando o recarregamento de recursos antigos. Conforme o escopo real da exposição, revogue sessões, rotacione tokens e senhas em um ambiente limpo; remover tags script não revoga ganchos e temporizadores já instalados.
- Verifique independentemente o endereço de depósito e a transação. Para a página que executa a carga, confirme o endereço de depósito original, a transação relacionada e o destino real da transferência por meio de canais confiáveis, e avalie o impacto com base no histórico da transação.
- Verificar scripts e restrições de saída de dados. Combinar configurações de negócios para controle de origem e integridade de scripts, verificando separadamente políticas como connect-src e img-src, restringindo o carregamento de scripts e a transmissão de dados para udeskqlobal[.]com.
IOC
Domain
udeskqlobal[.]com
URL
https[:]//udeskqlobal[.]com/deeps[.]js
https[:]//udeskqlobal[.]com/c[.]php
Endereço da carteira
BTC: bc1qhzppfj69ywp22swj50jwcfxdamg3ym245srng9
EVM: 0x9B6EcD0023a28E1391c5124eCe578A9751A337b2
TRON: TH4L5YAhhxtC8qALbZKbPZZgausbGi25nF
Solana: AFmCUe3nNbjTaC585CcdA3vvC9iWVR8YunooFKpaQx2Z
LTC: ltc1qwz0zp39ywl34kahvn9lyk7j5x63wsy9tcxhm3w
DOGE: DAoy2w8uvFtZ92q87s9qKEoHbWgV7mVThj
Arquivo malicioso
filename: udeskApi.2026-10-16.cached.js
SHA256: 45b4e8f160d8d5177819f6c1dc67acc7abbdc65eeaffc909e668799dc778bcf6
filename: deeps.js
SHA256: 57c1441c4f5bb3260981a2df64f9ff35f117abde0d8667c8c66a047880074c59
Sobre MistEye
MistEye é uma plataforma de inteligência de ameaças Web3 e monitoramento de segurança dinâmico desenvolvida internamente pela SlowMist, que fornece, por meio de API, capacidades de detecção de atividades maliciosas e alertas de risco na cadeia de suprimentos para o ecossistema de pacotes abertos.
Todos os pacotes maliciosos e IOC envolvidos nesta ação já foram integrados ao motor de detecção de ameaças MistEye; os desenvolvedores podem realizar detecção automatizada das dependências do projeto por meio da API, identificando rapidamente se houve correspondência com pacotes maliciosos conhecidos e obtendo recomendações de ação.


