Introducción

En julio de 2026, Confiant publicó un análisis detallado sobre SourTrade, una campaña de malvertising que ensambla ejecutables de Windows directamente en el navegador de la víctima, sin necesidad de distribuir un archivo completo en la red. La técnica explota el runtime legítimo de Bun (versión 1.1.30, según los samples analizados) y workers de navegador para generar un binario por sesión, variando su hash y eludiendo detecciones basadas en firmas estáticas. El ataque se dirige a usuarios de TradingView, Solana y Luno, simulando servicios legítimos para robar credenciales, interceptar tráfico y extraer fondos de billeteras de criptomonedas en 12 países y 25 idiomas.

Lo más preocupante no es solo el método de ensamblaje, sino que el malware no existe como archivo completo en la red en ningún momento. Cada víctima recibe una versión única del ejecutable, compuesta en tiempo real a partir de:

  • Un runtime de Bun (descargado desde purelogicbox[.]org).
  • Secciones de PE (Portable Executable) y bytecode JavaScriptCore cifradas en Base64 en /config.
  • Un flujo de bytes aleatorios generado con AES-CTR, que actúa como padding para evadir firmas antivirus.

Este enfoque no requiere explotaciones de navegador ni manipular la Mark of the Web (MotW). El archivo final se descarga con un Content-Disposition que atribuye la fuente a la landing page, no al dominio del runtime, lo que complica el análisis forense.

Qué ocurrió

Evolución desde técnicas previas: de StreamSaver.js a Bun

En abril de 2026, Confiant identificó una variante anterior de SourTrade que utilizaba StreamSaver.js (librería open-source para descargas por streaming) alojada en GitHub Pages para descargar el payload. El tráfico de red mostraba claramente la URL de GitHub como origen de la descarga, lo que facilitaba su bloqueo. Sin embargo, en la versión actual, el mecanismo de streaming se mantiene, pero el código ya no se descarga desde GitHub, sino que está embebido en la página. Esto elimina el rastro en logs de red que apuntaban a un dominio externo conocido.

La nueva técnica reemplaza StreamSaver.js por un SharedWorker que:

  1. Registra un ServiceWorker en /sw.js (página-escoped, no global).
  2. Inicia un worker en segundo plano que:
– Descarga /config desde un dominio secundario (ej: purelogicbox[.]org).

– Recupera un runtime de Bun (archivo .exe limpio) y datos cifrados (PE header, tabla de secciones, bytecode de app.js).

– Ensambla el ejecutable en memoria combinando:

– Fragmentos del runtime de Bun.

– El flujo aleatorio generado con AES-CTR (clave y nonce derivados de valores aleatorios por sesión).

– Los datos del atacante (PE header, secciones, bytecode).

  1. Transfiere el binario resultante al ServiceWorker como un stream y lo sirve con un Content-Disposition: attachment que apunta a la landing page original.

Componentes clave y versiones

ComponenteVersión/DetalleRol en la cadena de ataque
Bun1.1.30 (sample analizado)Runtime legítimo para compilar bytecode en ejecutables.
ServiceWorkerBLOCK21 registrado en la landing pageGestión de descargas y ensamblaje en segundo plano.
SharedWorkerEmbevido en la página, sin fetch externoGeneración del ejecutable final.
BLOCK22Endpoint que devuelve PE template, runtime URL y valores aleatorios (Base64).Fuente de datos para el ensamblaje.
AES-CTRModo de operación para generar el flujo de bytes aleatorios.Evita firmas estáticas y elude detecciones basadas en hash.
purelogicbox[.]orgDominio secundario (ejemplo) donde se aloja el runtime de Bun.Distribución del runtime limpio.
Landing pages12 países, 25 idiomas, impersonan TradingView, Solana, Luno.Punto de entrada para víctimas seleccionadas.
### Fases del ataque
  1. Fingerprinting y selección de víctimas:
– La landing page verifica si el visitante es un investigador de seguridad o un bot (ej: por User-Agent o IP conocida).

– Si es un objetivo válido, muestra una copia convincente del servicio impersonado (ej: TradingView falso).

– Si no, devuelve una página vacía.

  1. Preparación del ensamblaje:
– La página registra el ServiceWorker en /sw.js.

– Inicia el SharedWorker (embebido en JS) que:

– Solicita /config al dominio secundario.

– Recibe una respuesta Base64 con:

– Una plantilla de PE (header, tabla de secciones).

– La URL del runtime de Bun.

– Valores aleatorios (semilla para AES-CTR, tamaño del ejecutable).

– Descarga el runtime de Bun (archivo .exe limpio) desde purelogicbox[.]org.

  1. Generación del ejecutable:
– El worker:

– Decodifica los datos Base64 del /config.

– Genera un flujo de bytes aleatorio usando AES-CTR (clave derivable de los valores aleatorios de /config).

– Combina:

– Fragmentos fijos del runtime de Bun.

– El flujo aleatorio (como padding).

– Los datos del atacante (PE header, secciones, bytecode de app.js).

– El resultado es un ejecutable de Windows válido, pero único por sesión.

  1. Descarga y ejecución:
– El ServiceWorker sirve el binario resultante con un Content-Disposition: attachment que apunta a la landing page.

– La Mark of the Web (MotW) se mantiene, pero el origen del archivo se atribuye a la landing page, no al dominio del runtime.

Impacto para DevOps / Infraestructura / Cloud / Seguridad

Riesgo para equipos de seguridad

El impacto directo de SourTrade se centra en la evasión de detecciones tradicionales, pero con consecuencias concretas:

  • Detección por hash inútil: Cada ejecutable generado tiene un hash único (ej: los 3 hashes SHA-256 publicados por Confiant son distintos entre sí). Esto invalida firmas antivirus basadas en hash y análisis estático de archivos.
  • Tráfico «limpio»: El runtime de Bun y los datos Base64 viajan por la red, pero no existe un archivo malicioso completo en ningún momento. Solo hay fragmentos (runtime limpio, bytecode, PE template) que, combinados, forman el ejecutable.
  • Persistencia del engaño: La landing page usa dominios legítimos (ej: dominios de servicios como TradingView) y técnicas de domain shadowing o fast flux para alojar el /config y el runtime. Esto dificulta el bloqueo por IP o DNS.

Impacto cuantitativo

  • Alcance geográfico: 12 países (EE.UU., Reino Unido, Alemania, Francia, Japón, Corea del Sur, entre otros) y 25 idiomas.
  • Objetivos: Usuarios de TradingView, Solana y Luno (plataformas de trading y criptomonedas).
  • Payload documentado: Confiant no confirma el payload final (Bitdefender identificó en septiembre de 2025 un stealer llamado JSCEAL o WeevilProxy en campañas similares, pero no se ha vinculado directamente a los samples de SourTrade).
  • Capacidades del malware: Según Bitdefender, el payload anterior incluía:
– Robo de credenciales.

– Keylogging.

– Intercepción de tráfico.

– Robo de fondos de billeteras.

– Acceso remoto.

Riesgo para infraestructura

  • Tráfico de red: Los dominios maliciosos (ej: purelogicbox[.]org) y las landing pages pueden generar alertas en logs de balanceadores o firewalls, pero no por contener un archivo malicioso completo, sino por patrones como:
– Solicitudes a /config con respuestas Base64 anómalas.

– Conexiones a dominios secundarios no relacionados con el servicio impersonado.

– Uso de workers de navegador (ServiceWorker, SharedWorker) en dominios no esperados.

  • Endpoint: Una vez descargado, el ejecutable se ejecuta con los permisos del usuario, lo que puede llevar a:
– Compromiso de credenciales.

– Robo de fondos en billeteras de criptomonedas.

– Persistencia en el sistema (si el ejecutable se copia a directorios como %APPDATA% o %TEMP%).

Detalles técnicos

Vectores y componentes específicos

1. Registro del ServiceWorker y SharedWorker

La landing page registra un ServiceWorker en /sw.js con este código embebido (simplificado):

// Código embebido en la landing page (no se descarga desde un URL externo)
navigator.serviceWorker.register('/sw.js').then(() => {
  const sharedWorker = new SharedWorker('data:application/javascript;base64,...');
  sharedWorker.port.start();
});

El ServiceWorker (/sw.js) maneja la descarga final:

// /sw.js
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('sourtrade-cache').then((cache) => {
      return cache.addAll(['/config', '/runtime/bun.exe']);
    })
  );
});

self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('/download')) {
    event.respondWith(
      new Response(ensamblarExecutable(), {
        headers: { 'Content-Disposition': 'attachment; filename=setup.exe' }
      })
    );
  }
});

2. Endpoint /config y datos Base64

La respuesta de /config incluye datos estructurados en Base64. Ejemplo de estructura (simplificado):

{
  "template": "PE_HEADER...",
  "runtime_url": "https://purelogicbox[.]org/bun/1.1.30/bun.exe",
  "pe_sections": {
    ".bun": "BASE64_BYTECODE_APPJS"
  },
  "aes_seed": "RANDOM_SEED_16_BYTES",
  "aes_nonce": "RANDOM_NONCE_8_BYTES",
  "session_size": 1048576
}

3. Generación del ejecutable con Bun

Bun (versión 1.1.30) se usa para compilar el bytecode en un ejecutable. El worker:

  1. Descarga el runtime de Bun desde purelogicbox[.]org.
  2. Decodifica los datos Base64 del /config.
  3. Genera el flujo de bytes aleatorio con AES-CTR (usando la biblioteca crypto de Node.js embebida en Bun):
const crypto = require('crypto');
const seed = Buffer.from(config.aes_seed, 'base64');
const nonce = Buffer.from(config.aes_nonce, 'base64');
const cipher = crypto.createCipheriv('aes-256-ctr', seed, nonce);
let randomStream = cipher.update(Buffer.alloc(config.session_size));
randomStream = Buffer.concat([randomStream, cipher.final()]);
  1. Combina los fragmentos para formar el ejecutable final:
function ensamblarExecutable() {
  const bunRuntime = fs.readFileSync('/cache/bun.exe');
  const peHeader = Buffer.from(config.template.pe_header, 'base64');
  const peSections = Buffer.from(config.template.sections, 'base64');
  const bytecode = Buffer.from(config.pe_sections['.bun'], 'base64');
  const assembled = Buffer.concat([bunRuntime.slice(0, 0x400), peHeader, peSections, randomStream, bytecode]);
  return assembled;
}

4. Descarga final con MotW

El ServiceWorker devuelve el ejecutable con un Content-Disposition que apunta a la landing page, preservando la Mark of the Web:

HTTP/1.1 200 OK
Content-Disposition: attachment; filename=TradingView_Setup.exe
Content-Type: application/x-msdownload
Content-Length: 1048576
Source: https://tradingview-fake[.]com/download

Señales de alerta en logs

Log/EndpointPatrón a buscarHerramienta para detectar
BLOCK50Respuesta con datos Base64 anómalos (PE header, bytecode JavaScriptCore).WAF (ModSecurity, AWS WAF), SIEM (Splunk).
Dominios secundariosConexiones a BLOCK51 o similares desde dominios de servicios legítimos.Firewall, DNS logs, Threat Intelligence.
Workers de navegadorRegistro de BLOCK52 o BLOCK53 en dominios no esperados.Browser DevTools, logs de CDN.
BLOCK54Solicitudes a endpoints que devuelven archivos BLOCK55 con BLOCK56.EDR (CrowdStrike, SentinelOne), proxies.
## Qué deberían hacer los administradores y equipos técnicos

1. Bloquear dominios y endpoints conocidos

Añadir los dominios y IPs identificados por Confiant a listas de bloqueo en firewalls, proxies y soluciones DNS/EDR. Ejemplo para blocklists:

# Lista para firewalls (ej: pfSense)
185.143.223.45    purelogicbox[.]org
203.0.113.12      tradingview-fake[.]com
# Lista para DNS (ej: Pi-hole)
||purelogicbox[.]org^
||tradingview-fake[.]com^
Comando concreto para actualizar blocklists en WAF (ej: AWS WAF):
aws wafv2 update-rule-group \
  --rule-group-arn arn:aws:wafv2:us-east-1:123456789012:regional/rulegroup/... \
  --updates file://blocklist.json
(Donde blocklist.json contiene los dominios en formato de rule group de AWS WAF).

2. Monitorear patrones en logs

Configurar reglas en el SIEM o WAF para alertar cuando:

  • Se detecten respuestas Base64 en /config con patrones de PE header o bytecode.
  • Haya conexiones a dominios secundarios desde landing pages de servicios legítimos (ej: TradingView, Solana).
Regla para Splunk (SPL):
index=web sourcetype=access_* (url="/config" OR url="/download")
| eval is_base64=if(match(body, "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"), 1, 0)
| where is_base64=1 AND (match(body, "MZ") OR match(body, "Zl"))  # PE header o bytecode
| table _time, src_ip, url, body

3. Deshabilitar workers de navegador en dominios no autorizados

Si no se usan workers de navegador en tu infraestructura, bloquear su registro con políticas de CSP o headers HTTP:

Content-Security-Policy: worker-src 'none'; script-src 'self'
Ejemplo para Nginx:
location / {
  add_header Content-Security-Policy "worker-src 'none'; script-src 'self'";
}

4. Educar a usuarios finales

  • Regla de oro: Nunca descargar software desde anuncios o dominios no oficiales. Siempre usar el sitio oficial del proveedor (ej: tradingview.com, no tradingview-fake[.]com).
  • Verificar URLs: Comparar la URL de la landing page con la oficial (ej: https://tradingview.com vs https://tradingview-fake[.]com).
  • MotW: Enseñar a usuarios a verificar el origen de descargas en el navegador (el icono de descarga muestra la fuente real).

5. Fortalecer detecciones en endpoints

  • EDR: Configurar reglas para detectar:
– Ejecutables generados en %TEMP% o %APPDATA% con firmas no válidas.

– Procesos que inyecten código en navegadores (ej: msiexec.exe o rundll32.exe).

  • AV: Habilitar detección basada en comportamiento (ej: CrowdStrike’s IOA para descargas desde workers de navegador).

6. Analizar tráfico histórico

Si sospechas que tu organización fue afectada:

  • Buscar en logs:
– Solicitudes a /config con respuestas Base64.

– Descargas de ejecutables desde dominios secundarios.

  • Herramientas recomendadas:
– Zeek (anteriormente Bro) para análisis de tráfico.

– Volatility para análisis forense de endpoints.

Conclusión

SourTrade representa una evolución en las técnicas de malvertising: en lugar de distribuir un binario malicioso completo, el navegador se convierte en el ensamblador, utilizando herramientas legítimas como Bun y workers de navegador para generar ejecutables únicos por sesión. Esto evade detecciones basadas en hash y complica el análisis forense, pero no hace invencible al ataque: los componentes aún viajan por la red, y los patrones en logs (Base64 en /config, workers no autorizados, dominios secundarios) son detectables con configuraciones adecuadas.

La clave para mitigar este riesgo no es solo actualizar firmwares o parches, sino:

  1. Adoptar un enfoque de defensa en profundidad, combinando bloqueo de dominios, monitoreo de logs y educación de usuarios.
  2. Tratar cada fase de la cadena de ataque como crítica, desde el fingerprinting hasta la descarga final.
  3. Invertir en detecciones basadas en comportamiento, ya que las firmas estáticas son ineficaces contra técnicas como esta.

Para equipos de DevOps, el mensaje es claro: los workers de navegador y los runtimes legítimos pueden ser vectores de ataque. Validar el uso de estas tecnologías en tu infraestructura y aplicar políticas de CSP estrictas es tan importante como mantener actualizados los sistemas operativos.

Fuentes

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *