Un actor malicioso llevó a cabo un ataque a la cadena de suministro comprometiendo la infraestructura de dominio que servía el SDK web de AppsFlyer, inyectando un payload polimórfico de robo de criptomonedas en miles de sitios web. El ataque eludió los controles de seguridad mediante el secuestro de DNS a nivel de registrador, lo que permitió a los atacantes servir código malicioso desde lo que parecían ser endpoints legítimos de AppsFlyer. El script inyectado reemplazó la API nativa window.fetch, monitorizó el DOM en busca de direcciones de criptomonedas y envió los datos de las víctimas a servidores de comando y control bajo el control del atacante. El ataque también apuntó a entornos de servidor Node.js, exponiendo a riesgo los frameworks SSR y los pipelines de compilación.
Lo que muestra la telemetría de cside
Antes de que el incidente fuera ampliamente conocido, la telemetría de Script Insights de cside registró comportamientos inusuales del SDK web de AppsFlyer. A partir del 1 de marzo, los sistemas observaron que se estaban sirviendo dos hashes de script diferentes desde el endpoint oficial de AppsFlyer en toda la red monitorizada. Esta rotación comenzó antes de que el incidente fuera confirmado, lo que sugiere que los atacantes estaban probando su infraestructura de despliegue o sirviendo deliberadamente compilaciones polimórficas para evitar la detección.
La telemetría confirma que las principales plataformas cargaron el SDK comprometido. Los dominios específicos se están reteniendo mientras las organizaciones afectadas completan la remediación. Para conocer los controles prescriptivos que contienen este tipo de incidente, consulta nuestras mejores prácticas para proteger los scripts de terceros frente a compromisos de la cadena de suministro.
El vector de entrada: un secuestro de DNS a nivel de registrador
Los atacantes no vulneraron la infraestructura AWS de AppsFlyer ni sus repositorios internos. Obtuvieron el control mediante un secuestro de DNS a nivel de registrador.
Al comprometer la cuenta del registrador de dominio de appsflyer.com, los atacantes cambiaron sus servidores de nombres autoritativos. Los registros DNS muestran que al inicio del ataque, los servidores de nombres de appsflyer.com cambiaron de AWS Route 53 a ns1.gcorelabs.net (GCore CDN).
Una vez con el control del DNS, los atacantes enrutaron todo el tráfico de websdk.appsflyer.com a través de sus propios servidores. Interceptaron las solicitudes del SDK legítimo y entregaron un payload malicioso y degradado. Dado que el compromiso ocurrió en la capa DNS, este método eludió las defensas perimetrales estándar y las protecciones del lado del servidor.
El principal indicador forense: una degradación silenciosa de versión
Dado que los atacantes controlaban el DNS, no alteraron la lógica central del SDK de AppsFlyer, sino que simplemente lo utilizaron para entregar su payload.
El indicio más claro de manipulación fue una degradación silenciosa de versión. El SDK de referencia antes del incidente era la versión 0.0.60 (hash 7dbae31c...). Durante el ataque, la versión servida desde el endpoint oficial revirtió a 0.0.59 (hash db0c4f61...). Las actualizaciones legítimas no revierten números de versión, lo que convierte esto en evidencia clara de manipulación.
Al comparar los SDKs limpio y degradado, se identificaron tres líneas modificadas. Los atacantes eliminaron endpoints de banner específicos y cambiaron la cadena de versión interna.
// SDK limpio (0.0.60)
VERSION:"0.0.60"
banner.appsflyer.com/
banner.appsflyer.com/sb/
dismissInjectPixel // presente en la compilación limpia
// SDK comprometido (0.0.59)
VERSION:"0.0.59"
banner.appsflyer.com/ // endpoint .sb/ eliminado
// función dismissInjectPixel eliminada
Los atacantes evitaron alterar fvalid.appsflyer[.]com o wa.appsflyer[.]com/events, lo que habría roto las verificaciones de Integridad de Subrecursos. En su lugar, utilizaron el secuestro de DNS para enrutar todo el tráfico de appsflyer.com a través de su infraestructura, desde donde se servían los payloads maliciosos.
Tras el ataque, AppsFlyer trasladó su infraestructura a appsflyersdk[.]com y publicó una compilación limpia 0.0.61 en ese dominio. El dominio appsflyersdk[.]com, registrado en agosto de 2019, es propiedad de AppsFlyer.
Desofuscando los payloads polimórficos
El tráfico enrutado a través de los servidores comprometidos transportaba el payload de robo de criptomonedas. El análisis de tres archivos maliciosos reveló un enfoque de despliegue polimórfico con dos esquemas de ofuscación dirigidos a entornos de ejecución distintos.
Tipo de compilación 1: el payload para navegador (c7adfa8e)
El primer payload, de aproximadamente 170 KB, se ejecuta en el ámbito global window del navegador. Utiliza codificación base91 personalizada con un alfabeto de 83 caracteres para decodificar en tiempo de ejecución una tabla de cadenas de 786 entradas.
En un entorno sandbox, este payload reemplaza window.fetch y registra un MutationObserver para analizar el DOM en busca de direcciones de criptomonedas. También añade un módulo interno llamado NetHooksmith al objeto window (window.lIXMkR.NetHooksmith).
Tipo de compilación 2: los wrappers para Node.js (87e46457 y 9b0fac22)
La segunda variante, encontrada en dos compilaciones de aproximadamente 250 KB cada una, utiliza una técnica de ofuscación diferente orientada a entornos de servidor. En lugar de base91, estos archivos encierran la lógica central en constructores Function() anidados y decodifican cadenas mediante un array de constantes rotatorio combinado con String.fromCodePoint.
Estos wrappers utilizan objetos getter para engancharse a los contextos de Node.js: por ejemplo, get GKSDgsL(){return global} y get F1t0ak(){return exports}. Las aplicaciones Node.js, los frameworks SSR y los pipelines de compilación que importaron el SDK a través de npm o bundlers eran susceptibles.
Al interceptar las llamadas a fromCodePoint durante la ejecución en sandbox, se obtuvieron las cadenas decodificadas. Estas confirmaron que los wrappers ejecutaban la misma lógica central de reemplazo de fetch, pero utilizaban direcciones de billeteras separadas, lo que evidencia una infraestructura dedicada para el compromiso del lado del servidor.
Los dos clústeres de billeteras y la infraestructura C2
El análisis en sandbox identificó dos clústeres de billeteras del atacante claramente diferenciados. El payload para navegador (tipo de compilación 1) contenía un conjunto de direcciones, y los payloads para Node.js (tipo de compilación 2) contenían otro. Ambos los almacenaban en un objeto global walletAddresses.
Clúster 1 (payload para navegador c7adfa8e)
- ETH:
0x1C069d0c73087D0Bae687a6f74a807350dCe1829 - BTC:
bc1qr7ngtnsh66demm4vzt4kmqxkqj8sqprnuklalt - SOL:
4LJi6mAczxZWbUvbMEk5scKhUZNPvfMDTjaVADkPFSsK - XRP:
rntqwheGbZihkabxf6xqZkUKGfTVyRhT14 - TRX:
TV6WtAkS4aAMJb3Rt2bfs8LxggF8Kmqbd9
Clúster 2 (wrappers para Node.js 87e46457 y 9b0fac22)
- ETH:
0x782B93e52e62F25Bd002eeAA813B5A3fe49C9558 - BTC:
bc1q5nlx0exu0efldavw08wnjzpzluudaqh2qwlmjj - SOL:
B5hMeV7B72xqcjypzxxoPmLpNz3bi6VvZApQrnh8YwDP - XRP:
rEL7cB3jQNqtoym8oFJ36w1z3QLy9GjU - TRX:
T062f95a517fc05055b59e12c6f4b2a402
Endpoints de comando y control (C2)
Los payloads se comunicaron con dos endpoints C2 en la infraestructura secuestrada:
https://websdk[.]appsflyer[.]com/v1/api/plugin- obtenía nuevas direcciones de billeteras durante la inicialización.https://websdk[.]appsflyer[.]com/v1/api/process- cargaba las direcciones de billeteras exfiltradas y metadatos mediante un parámetro de consulta?rd=que contenía datos ofuscados con XOR.
Firmas de comportamiento y detección
Dado que los atacantes rotaron esquemas de ofuscación y direcciones de billeteras, las firmas estáticas como las reglas YARA resultaron ineficaces. Sin embargo, el comportamiento de los payloads es consistente y puede detectarse.
Los equipos de seguridad deben buscar estos indicadores:
- Salida por consola: Todos los payloads imprimen "Generating new wallets..." en la consola durante la inicialización.
- Reemplazo de
fetch: El payload sobrescribe la API nativafetchpara interceptar las solicitudes salientes que contienen direcciones de criptomonedas. - Contaminación de objetos globales: El payload crea un objeto global
walletAddresses; la variante para navegador añadewindow.lIXMkR.NetHooksmith. - Supresión de consola: El payload para navegador utiliza 32 referencias a métodos de
consolepara ocultar advertencias y errores. - Seguimiento de mutaciones del DOM: El payload para navegador registra un
MutationObserverpara analizar los nuevos elementos del DOM en busca de patrones de direcciones de criptomonedas.
Más allá del incidente: la superficie de fingerprinting del SDK legítimo
La revisión del SDK limpio (hash 7dbae31c) reveló que el plugin PBA legítimo de AppsFlyer recopilaba datos extensos de fingerprinting del dispositivo, incluyendo comprobaciones de fuentes en canvas, detección de bloqueadores de anuncios, detección de bots y acceso a localStorage, sessionStorage e indexedDB.
El SDK también carga código adicional desde fvalid.appsflyer[.]com/af/cp.sdk.1.2.7.js en tiempo de ejecución. Aunque es habitual en los SDKs de marketing, esto representa un riesgo continuo en la cadena de suministro. Las organizaciones deben evaluar la necesidad de dicho seguimiento y aplicar Políticas de Seguridad de Contenido (CSP) e Integridad de Subrecursos (SRI) estrictas a todo el código de terceros.
Cómo podría haber ayudado cside
Un secuestro de dominio a nivel de registrador elude las defensas perimetrales y el análisis estático. El enfoque de seguridad del lado del cliente de cside detecta y bloquea este tipo de ataques en tiempo real mediante los siguientes mecanismos:
- Detección de anomalías de comportamiento: cside monitoriza las acciones de los scripts en lugar de las firmas estáticas, generando alertas ante intentos de sobrescribir
window.fetcho acceder a entradas de criptomonedas. - Bloqueo de exfiltración de red: Si el payload se ejecuta, los controles de red de cside pueden bloquear las conexiones salientes hacia los servidores C2, impidiendo la recuperación de billeteras y el robo de datos.
- Alertas por rotación de hashes: La telemetría de cside detectó la alternancia de hashes de scripts días antes de que el ataque se hiciera público, permitiendo una investigación temprana.
- Detección de degradación de versión: cside registra las versiones exactas y los hashes de los scripts de terceros. Una degradación silenciosa de
v0.0.60av0.0.59habría activado una alerta inmediata de manipulación.
Al aplicar medidas de confianza cero en el lado del cliente, cside impide que los scripts de proveedores comprometidos exploten la confianza de los usuarios.
Indicadores de compromiso (IOCs)
- Dominio:
appsflyer[.]com- Dominio legítimo secuestrado a nivel de registrador - Servidor de nombres:
ns1.gcorelabs.net- Servidor de nombres bajo control del atacante durante el secuestro - URL (C2):
https://websdk[.]appsflyer[.]com/v1/api/plugin- Endpoint C2 del payload (rotación de billeteras) - URL (C2):
https://websdk[.]appsflyer[.]com/v1/api/process- Endpoint C2 del payload (exfiltración) - Parámetro de URL:
?rd=- Contiene datos de exfiltración ofuscados con XOR - Billetera (ETH):
0x1C069d0c73087D0Bae687a6f74a807350dCe1829- Clúster 1 (payload para navegador) - Billetera (BTC):
bc1qr7ngtnsh66demm4vzt4kmqxkqj8sqprnuklalt- Clúster 1 (payload para navegador) - Billetera (SOL):
4LJi6mAczxZWbUvbMEk5scKhUZNPvfMDTjaVADkPFSsK- Clúster 1 (payload para navegador) - Billetera (ETH):
0x782B93e52e62F25Bd002eeAA813B5A3fe49C9558- Clúster 2 (wrappers para Node.js) - Cadena de consola: "Generating new wallets..." - Salida en texto plano de todos los payloads
- Objeto global:
walletAddresses- Inyectado por todas las variantes del payload - Objeto global:
window.lIXMkR.NetHooksmith- Inyectado por el payload para navegador - Cadena de versión:
0.0.59- Versión del SDK degradada que indica manipulación
Recomendaciones
- Compare inmediatamente la versión y el hash del SDK servido desde cualquier endpoint de AppsFlyer que consuma con hashes conocidos como válidos; trate las degradaciones silenciosas como alertas de manipulación de alta prioridad.
- Bloquee o redirija a sinkhole las solicitudes salientes hacia los endpoints C2 identificados y los servidores de nombres asociados hasta que la remediación esté completa.
- Refuerce la CSP y aplique SRI a los recursos de terceros donde sea factible; considere el autoalojamiento de scripts críticos de proveedores tras verificar su integridad.
- Analice los pipelines de compilación del lado del servidor y los despliegues SSR en busca de los indicadores del wrapper para Node.js descritos anteriormente y rote las credenciales afectadas.
- Implemente cside para vigilar las sobreescrituras de API (como
fetch) y el análisis de mutaciones del DOM por parte de scripts de terceros.
Este incidente no es un caso aislado. Para profundizar en cómo el blanqueo de infraestructura extiende la amenaza más allá del compromiso de un único proveedor, consulta nuestro análisis de la infraestructura de polyfills sancionada.
Los detalles forenses, los hashes de archivos y la telemetría adicional están disponibles bajo solicitud para las organizaciones afectadas y los equipos de respuesta a incidentes.
Nota: Esta publicación resume los hallazgos de la telemetría de Script Insights de cside y el análisis en sandbox. Algunos dominios específicos y IOCs adicionales se retienen mientras las partes afectadas llevan a cabo la remediación.





