SlowMist: Udesk JS malicioso roba datos y modifica direcciones de transferencia

iconMetaEra
Compartir
AI summary iconResumen
SlowMist descubrió un script JS malicioso en el sistema Udesk, vinculado a noticias en cadena sobre plataformas comprometidas como mgbx.com y bitxex.io. El script, cargado a través de udeskApi.2026-10-16.cached.js y deeps.js, roba datos de sesión y modifica las direcciones de recarga. Los atacantes utilizan un cargador remoto para inyectar código, lo que pone en riesgo el robo de fondos. Los datos de inflación y la volatilidad del mercado pueden amplificar las pérdidas para los usuarios afectados. La brecha pone de manifiesto preocupaciones de seguridad urgentes en múltiples exchanges.
¿Cómo puede un ataque de inyección de script comprometer simultáneamente los datos del usuario y los fondos transferidos?

Autor del artículo, fuente: Slow Mist Tech

Context

Recientemente, el personal de seguridad de SlowMist, durante la minería diaria de inteligencia de amenazas, detectó una actividad de ataque que involucraba la toxicación de scripts relacionados con el sistema de servicio al cliente Udesk. El equipo obtuvo posteriormente dos muestras de JavaScript: udeskApi.2026-10-16.cached.js y deeps.js, y realizó un análisis para rastrear cómo el código malicioso se infiltraba en las páginas a través de los scripts de servicio al cliente y qué efectos tenía sobre los datos de los usuarios y las operaciones comerciales.

La revisión paso a paso de la muestra reveló dos tipos de riesgos: un script malicioso que recopila datos de sesión e información sensible enviada por el usuario en la página, mientras modifica simultáneamente la dirección de depósito y copia el contenido según las reglas del sitio. El primero podría permitir a los atacantes suplantar sesiones de inicio de sesión o tomar el control de cuentas, mientras que el segundo podría hacer que los usuarios transfieran fondos de depósito a una dirección de cobro sustituida. A partir del punto de carga del script de servicio al cliente, seguimos la lógica de lectura de datos, envío de red y modificación de página para reconstruir la implementación y las condiciones de activación de ambos comportamientos.

MistEye response

MistEye es un sistema de inteligencia de amenazas Web3 y monitoreo de seguridad dinámico desarrollado internamente por SlowMist, que integra capacidades de monitoreo de seguridad y agregación de inteligencia para proporcionar a los usuarios alertas de riesgo en tiempo real y protección de activos.

MistEye ha sincronizado el riesgo inmediatamente a través de canales de alerta de inteligencia y notificaciones a clientes.

Cargador malicioso y mecanismo de carga de carga remota

Al abrir udeskApi.2026-10-16.cached.js, se pueden ver el código para funciones como el botón de servicio al cliente, el iframe de chat, el seguimiento de visitantes y la comunicación de mensajes. Al continuar revisando el final del archivo, después del cuerpo principal hay una función independiente: decodifica dos cadenas mediante _ud(), crea elementos y los inserta en el head del documento actual.

Esta sección no especifica directamente el nombre de la etiqueta ni la URL remota. Si solo se busca el nombre de dominio en texto plano, es fácil omitir el punto de carga. Al revisar la implementación de _ud(), descubrimos que toma dos caracteres hexadecimales a la vez y los convierte en caracteres; al expandir las constantes, el objetivo de carga se vuelve claro.

736372697074 se decodifica como script, otra constante se decodifica como https[:]//udeskqlobal[.]com/deeps.js. El dominio, con qlobal que comienza con la letra q, debe conservar esta ortografía durante la búsqueda. El cargador establece el script como asíncrono y luego lo inserta en la página; cuando se alcanza esa posición y las políticas del navegador y la red lo permiten, el código remoto puede ingresar al documento actual.

La carga correspondiente a esta URL es deeps.js. El enfoque de la investigación pasó del SDK de soporte a la carga en sí. El script clásico de terceros se ejecuta en el contexto del documento incrustado, y los datos a los que puede acceder dependen de la página o iframe en que se ejecute. La ventana de chat de soporte utiliza un iframe y no aísla automáticamente los scripts cargados en la página principal.

Mecanismo de recopilación de datos web y alcance

deeps.js comienza leyendo window.location.hostname y genera la configuración C según las reglas de los tres sitios. Para determinar qué páginas serán recopiladas, esta configuración por sí sola no es suficiente: se debe rastrear la ubicación de la evaluación de salida para determinar si la restricción aplica a todo el script o solo a un módulo específico.

Al seguir el flujo de control, vemos que la lectura de cookies y almacenamiento web, el envío de instantáneas de inicio, y los hooks de formularios y solicitudes de autenticación aparecen todos antes de if (!C) return; A continuación, se muestran las instrucciones de envío de instantáneas y el hook XHR final en el orden del código fuente; los comentarios indican el código omitido entre medio, correspondiente a la vista formateada D:L100, D:L151–L166.

La ubicación de la salida está clara en cuanto al alcance del impacto: incluso si el hostname no coincide con las reglas de los tres sitios, el script primero entrará en la ruta de recopilación de datos e instalará los ganchos, y luego saldrá del módulo de direcciones. Al investigar páginas expuestas, no se debe buscar únicamente alrededor de la configuración de estos tres sitios.

Al iniciarse, la carga lee las Cookies, localStorage y sessionStorage accesibles en la página actual. Estos lugares pueden almacenar el estado de inicio de sesión, perfiles de usuario y datos empresariales; si contienen tokens de inicio de sesión válidos y reutilizables, un atacante que los obtenga podría suplantar la sesión del usuario. El script también incluye la URL de la página principal y el origen del documento actual, para enviar estos datos junto con la página de origen.

El proceso de recopilación es tolerante a errores por elemento. Cuando falla la lectura cruzada de la URL principal, el script reemplaza el valor con x y continúa procesando los demás campos; ambos tipos de almacenamiento de páginas web se serializan en JSON. El alcance de las cookies se limita al contenido legible por document.cookie, y las cookies HttpOnly no están incluidas.

El script también mantiene entradas para los datos enviados posteriormente. Cuando el usuario envía el formulario, recorre los elementos input, select y textarea, copia el contenido no vacío y luego continúa con el proceso de envío original. Los campos reales completados en la página, como nombre de usuario, contraseña y código de verificación, podrían ingresar en rutas adicionales de envío de datos, lo que, si se filtran, podría utilizarse para iniciar sesión en la cuenta o tomar el control de la misma.

Esta ruta implementa el envío envolviendo HTMLFormElement.prototype.submit y escuchando eventos submit en la fase de captura. Para páginas que envían datos directamente a través de la interfaz, el script también envuelve fetch y XHR: cuando la solicitud tiene un cuerpo y la URL contiene palabras clave como login|signin|auth|register|signup|password, se copia el contenido correspondiente y se conserva la llamada original a la solicitud. En la rama de fetch, se requiere adicionalmente que la URL sea una cadena y que el cuerpo provenga de las opciones de la solicitud; cuando objetos como FormData se serializan directamente en JSON, el contenido recopilado puede carecer de campos reales.

Mecanismo de fuga de datos y canal de respaldo

La entrada de recopilación anterior finalmente llama a la misma función _send(). Al rastrear esta función, se puede ver que el receptor fijo es https[:]//udeskqlobal[.]com/c.php. La instantánea de inicio utiliza los campos s, o, c, l, ss para transportar respectivamente la dirección de la página, la fuente actual, las cookies legibles y dos tipos de almacenamiento web; las solicitudes de formulario y autenticación posteriores se envían al activarse.

La función extrae los parámetros después del signo de interrogación en la URL y los incluye en el cuerpo de una solicitud POST asincrónica, estableciendo Content-Type: application/x-www-form-urlencoded. A continuación, se conserva completamente la función de envío (D:L45–L60):

La ruta de envío también incluye un mecanismo de respaldo para solicitudes de imagen: cuando ocurre un error XHR o una anomalía sincrónica durante el envío, el script crea un objeto Image, asigna la URL con parámetros a src y intenta enviar nuevamente los datos mediante GET. La URL se trunca a los primeros 8.000 caracteres JavaScript; el contenido más largo puede no completarse.

Al interpretar esta ruta, es necesario distinguir entre "envío de solicitud" y "lectura de respuesta". El script no lee la respuesta de c.php; una solicitud POST cruzada que cumple con los criterios de solicitud simple puede enviarse primero, y luego el navegador restringe la lectura de la respuesta, por lo que los errores CORS pueden ocurrir simultáneamente con el envío de la solicitud. La inspección de registros debe revisar tanto el cuerpo del POST como los parámetros GET de la imagen, mientras que la política de salida debe verificar por separado connect-src e img-src. Un formulario normal que desencadene una navegación de documento también puede afectar la capacidad de completar solicitudes asíncronas.

Hasta aquí, el destino de los datos de la sesión web y el contenido enviado posteriormente está claro. Sin embargo, después de la verificación de salida del sitio, la carga útil aún conserva otro conjunto de operaciones: identificar el formato de dirección, modificar el texto de la página y asumir el control de la ruta de copia. Este código lleva la investigación más allá hacia el servicio de depósitos.

Reemplazo de direcciones de depósito y mecanismo de secuestro del portapapeles

Tras if (!C) return; el script entra en el módulo de direcciones. Las tres reglas iniciales de hostname ahora tienen un propósito claro: coincidir con mgbx[.]com, bikingex[.] y bitxex[.]io para seleccionar los selectores de elementos del botón de dirección y copia en distintas páginas.

Estas expresiones regulares no tienen anclajes de inicio y fin, por lo que su rango de coincidencia es más amplio que una comparación precisa de nombres de dominio. La regla de página también verifica si la location.href completa, los parámetros de consulta o los fragmentos contienen palabras clave como deposit, recharge, assets, etc. Una vez que se detectan la página, el elemento o el formato de dirección, el script escanea cada 200 milisegundos y reemplaza las direcciones de depósito identificadas con el valor configurado. Si el usuario completa una transferencia válida utilizando la dirección reemplazada, el destino del pago se convertirá en esa dirección.

Tres sucursales de sitios comparten seis valores de configuración, marcados en el código como BTC, EVM, TRON, Solana, LTC y DOGE. La identificación de direcciones se basa únicamente en la forma de los caracteres y el orden de coincidencia, sin verificar la red seleccionada por el usuario ni el código de verificación de la dirección, y también puede identificar incorrectamente identificadores comerciales comunes.

Siga verificando el código copiado; puede observar que la muestra interviene simultáneamente en la visualización de la página y en el contenido del portapapeles. De esta manera, incluso si el usuario compara la dirección de la página con el resultado copiado, podría obtener valores manipulados consistentes. Las tres rutas son:

  • Empaquetar la API del portapapeles. navigator.clipboard.writeText primero llama a R() para reemplazar los parámetros, luego los pasa al método original. Esta ruta solo está restringida por la configuración de hostname, no vuelve a verificar las condiciones de la página de depósito ni depende del escaneo DOM de elementos ya alcanzados.
  • Reemplazar el botón de copia. El script clona el botón coincidente, instala un nuevo detector de clic y reemplaza el nodo original. El nuevo detector impide la acción predeterminada y la propagación del evento, e intenta copiar la dirección guardada en la variable compartida _cur.
  • Interceptar el evento copy. Cuando _cur no esté vacío y se cumplan las reglas de la página, el detector en document cambiará el contenido copiado por _cur, sin verificar si el texto seleccionado por el usuario es una dirección.

En este caso, el envoltorio de la API del portapapeles y el detector de copia están adyacentes en el código fuente (D:L260–L275), pero tienen condiciones de activación diferentes:

_cur guarda la última dirección reemplazada realmente. Cuando hay múltiples direcciones en la misma pantalla, el reemplazo posterior sobrescribe el registro anterior, y varios botones pueden copiar el mismo valor. Si la página ya muestra una dirección de configuración al cargarse, el escaneo no inicializará _cur, por lo que los nuevos detectores de botones no escribirán contenido; los atributos de eventos integrados en HTML conservados por clonación aún pueden participar en el manejo de eventos.

Durante el análisis, se encontró un defecto de implementación que afecta la evaluación del comportamiento: el script intenta leer el descriptor de propiedad propio de textContent desde Element.prototype, mientras que la definición estándar de la propiedad se encuentra en Node.prototype. Bajo la relación de prototipos estándar, el acceso posterior a .set generará una excepción. Tras fallar esta rama, el catch ignora la excepción; al revisar el código anterior y posterior, se observa que el sondeo ya está registrado y los ganchos de copia posteriores se instalarán según sus respectivas condiciones. Un error en una sola rama no interrumpe el módulo de secuestro de direcciones.

Resumen

Tras rastrear el cargador al final del script del servicio al cliente, determinamos que el objetivo del ataque es recolectar datos utilizables para suplantar sesiones o iniciar sesión en cuentas, además de modificar las direcciones de recepción en las páginas de depósito y las operaciones de copia por valores de configuración. El primero no está sujeto a las restricciones de configuración de los tres sitios, mientras que el segundo se activa según el sitio y la ruta de copia específica; durante la investigación, es necesario cubrir distintos escenarios expuestos.

Las empresas que aún cargan scripts relacionados deben dejar de distribuirlos, gestionar las credenciales expuestas y verificar los objetivos de recarga mediante registros confiables de fondo y transacciones.

Sugerencia

  1. Secure and cease distribution of contaminated resources. If production still loads related scripts, block them as soon as possible after saving the actual response, request chain, cache information, and collection time; restore from a trusted version verified independently, and check site hosting, CDN, build, and tag management configurations.
  2. Buscar carga y registros de exfiltración. Consulta combinada para dominios maliciosos, dos rutas y hashes de archivos; los registros de exfiltración también verifican el cuerpo POST y los parámetros GET. Al investigar scripts comprimidos, también buscar URLs hexadecimales en el cargador para evitar omitir detectar texto plano.
  3. Finalice el documento comprometido y descarte las credenciales expuestas. Cierre completamente las páginas o documentos WebView relacionados para evitar la recarga de recursos antiguos. Según el alcance real de la exposición, revoque sesiones, rote tokens y contraseñas desde un entorno limpio; eliminar las etiquetas script no revoca los detectores y temporizadores ya instalados.
  4. Verifique independientemente la dirección de depósito y la transacción. Para la página que ejecuta la carga, verifique mediante canales confiables la dirección de depósito original, la transacción relacionada y el destino real de la transferencia, y evalúe el impacto según el registro de transacciones.
  5. Verificar scripts y restricciones de salida de datos. Combinar la configuración del negocio con el control de origen e integridad de scripts, verificando por separado las políticas como connect-src e img-src, y restringir la carga de scripts y la transmisión de datos hacia udeskqlobal[.]com.

IOC

Domain

udeskqlobal[.]com

URL

https[:]//udeskqlobal[.]com/deeps[.]js

https[:]//udeskqlobal[.]com/c[.]php

Wallet address

BTC: bc1qhzppfj69ywp22swj50jwcfxdamg3ym245srng9

EVM: 0x9B6EcD0023a28E1391c5124eCe578A9751A337b2

TRON: TH4L5YAhhxtC8qALbZKbPZZgausbGi25nF

Solana: AFmCUe3nNbjTaC585CcdA3vvC9iWVR8YunooFKpaQx2Z

LTC: ltc1qwz0zp39ywl34kahvn9lyk7j5x63wsy9tcxhm3w

DOGE: DAoy2w8uvFtZ92q87s9qKEoHbWgV7mVThj

Archivos maliciosos

filename: udeskApi.2026-10-16.cached.js

SHA256: 45b4e8f160d8d5177819f6c1dc67acc7abbdc65eeaffc909e668799dc778bcf6

filename: deeps.js

SHA256: 57c1441c4f5bb3260981a2df64f9ff35f117abde0d8667c8c66a047880074c59

Sobre MistEye

MistEye es una plataforma de inteligencia de amenazas Web3 y monitoreo de seguridad dinámico desarrollada internamente por SlowMist, que ofrece mediante API la detección de actividades maliciosas y alertas de riesgos en la cadena de suministro para el ecosistema de paquetes de código abierto.

Todos los paquetes maliciosos y IOC involucrados en esta acción ya están integrados en el motor de detección de amenazas MistEye. Los desarrolladores pueden realizar detecciones automatizadas de las dependencias del proyecto mediante API para determinar rápidamente si coinciden con paquetes maliciosos conocidos y obtener recomendaciones de acción.

Descargo de responsabilidad: La información contenida en esta página puede proceder de terceros y no refleja necesariamente los puntos de vista u opiniones de KuCoin. Este contenido se proporciona solo con fines informativos generales, sin ninguna representación o garantía de ningún tipo, y tampoco debe interpretarse como asesoramiento financiero o de inversión. KuCoin no es responsable de ningún error u omisión, ni de ningún resultado derivado del uso de esta información. Las inversiones en activos digitales pueden ser arriesgadas. Evalúa con cuidado los riesgos de un producto y tu tolerancia al riesgo en función de tus propias circunstancias financieras. Para más información, consulta nuestras Condiciones de uso y la Declaración de riesgos.