PhantomSync: Los paquetes de criptomonedas de npm ocultan al ladrón de billeteras.

PhantomSync: ocho paquetes npm para desarrolladores de criptomonedas ocultan un dropper retardado y autopersistente.

TL; DR

Un único editor de npm envió ocho pequeños paquetes cuyos nombres parecen bloques de construcción cotidianos para el desarrollo de blockchain y billeteras, base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, y crypto-validate-libCada uno contiene una utilidad funcional. Sin embargo, después de dicha utilidad, se añade un bloque de código autoejecutable que se ejecuta en el momento en que se importa el módulo.

Aproximadamente 37 segundos después de la importación, ese bloque decodifica una carga útil que se envía dentro del paquete disfrazado de un dispositivo de prueba, la escribe en un archivo oculto en el directorio principal del usuario, se registra para reiniciarse en cada login Funciona en Windows, macOS y Linux, y ejecuta el script decodificado como un proceso independiente. Esto no se ejecuta durante la instalación de npm; simplemente espera a que el código se importe y se ejecute, lo cual es un proceso más silencioso que la instalación.

La carga útil no es opaca. Se envía como base64 simple, por lo que decodificar el "dispositivo de prueba" recupera la segunda etapa por completo: una Ladrón de monederos de criptomonedas y Secretos que espera a que la máquina esté inactiva, recopila claves privadas y frases semilla, cifra cada hallazgo con una clave RSA-4096 codificada y lo extrae fijándolo al almacenamiento público IPFS, enviando una señal cada 12 horas.

Realizamos un seguimiento del clúster como Sincronización fantasmaLos ocho paquetes estaban disponibles en el registro de npm en el momento del análisis, publicados bajo una única cuenta.

Ecosistemanpm
Paquetesbase58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, crypto-validate-lib
Plataformas objetivoWindows, MacOS, Linux
Comportamiento centralEl mecanismo de descarga retardada en el momento de la importación se oculta como un dispositivo de prueba; instala persistencia multiplataforma.
carga útilLadrón de monederos de criptomonedas y Secretos, cifrado RSA-4096, exfiltración a través de fijación IPFS pública.

Anatomía de ataque

A primera vista, cada paquete parece insignificante. utilidades base58, por ejemplo, son unos pocos kilobytes de código auxiliar Base58 / Bitcoin-WIF sin dependencias, exactamente lo que promete el nombre. El código relevante se encuentra después el módulo módulo.exportaciones, donde es improbable que un lector que hojea la parte superior del archivo mire: una función autoejecutable que se programa con un temporizador.

La cadena de operaciones, reconstruida a partir del código fuente del paquete, funciona de la siguiente manera:

1. Package is required() by the host project 2. A self-invoking function schedules a callback ~37,000 ms later (setTimeout) 3. On fire, the callback reads test/fixtures/keypairs.dat (a base64 blob) 4. It base64-decodes that blob into a Node.js script 5. It writes the script to ~/.cache-db/.node-sync/syncd.js (mode 0o700) 6. It installs login-persistence for that script (see below) 7. It spawns "node syncd.js" as a detached process

Dos decisiones de diseño destacan.

La carga útil se transporta como un dispositivo de prueba. La segunda etapa no está escrita como código obvio. Vive en test/fixtures/keypairs.dat, un archivo base64 cuyo nombre se mezcla con un paquete que afirma manejar pares de claves. Para un humano que hojea el tarball, parece datos de muestra; para el código adjunto, es un script para decodificar y ejecutar. El dropper en sí no contiene ninguna dirección de red (esas se encuentran en la segunda etapa), pero no hay ofuscación adicional: el fixture es una sola capa de base64, por lo que decodificarlo (base64 -d) recupera el total syncd.js y su comportamiento en la red. La siguiente sección explica qué hace esa etapa recuperada.

La detonación se retrasa y está ligada a la importación, no a la instalación. Porque el disparador es requerir () Además de un temporizador de ~37 segundos en lugar de un gancho de instalación, el comportamiento evita las comprobaciones que solo observan el npm instalar paso, y la demora dura más que muchas ejecuciones breves de sandbox y CI. Para cuando se ejecuta algo, la instalación que descargó el paquete ya ha terminado hace mucho tiempo.

Una vez que el script decodificado esté en el disco en ~/.cache-db/.node-sync/syncd.js — una ruta elegida para leerse como un directorio de caché rutinario — el dropper hace que sobreviva a los reinicios en las tres plataformas principales:

  • Linux: una entrada cron que reinicia el script. La entrada se instala filtrando el crontab existente a través de grep -v syncd, lo cual tiene el efecto secundario de dejar la nueva entrada fuera de una lista simple que busca el mismo nombre.
  • ventanas: una tarea programada llamada Sincronización de nodos de Windows, programado para repetirse con un intervalo de 12 minutos.
  • Mac OS: un trabajo de lanzamiento etiquetado com.apple.syncd, presente en varios de los paquetes, una etiqueta que imita un servicio legítimo del sistema Apple.

A continuación, el script se inicia inmediatamente como un proceso independiente, por lo que continúa ejecutándose después de que finalice el programa que lo importa.

¿Qué hace la segunda etapa?

Debido a que el accesorio es una sola capa base64, la segunda etapa se decodifica limpiamente y se puede leer por completo. Los ocho paquetes llevan una de las tres variantes del mismo script, que se identifica en un comentario de encabezado como phantom syncd v3 — topo durmiente (“topo durmiente”). Su trabajo consiste en robar material de monederos de criptomonedas y al desarrollador Secretos, y enviarlos fuera de la máquina. Funciona siguiendo estos pasos:

  • 1. Espere hasta que la máquina esté inactiva. Antes de hacer nada, syncd.js Comprueba cuánto tiempo ha estado inactivo el usuario y solo continúa si se supera un umbral (alrededor de 15 minutos). xprintidle en Linux ioreg HIDIdleTime en macOS y una consulta de tiempo de inactividad de PowerShell en Windows. Por lo tanto, la recolección de datos tiende a ocurrir cuando nadie está frente al teclado.
  • 2. Consigue un interruptor de activación controlado a distancia.. El script obtiene una pequeña configuración de un punto de entrega muerto antes de actuar. La fuente principal es una URL sin procesar de un gist de GitHub (gist.githubusercontent.com/juang55/…/cfg.txt); el script solo se activa si esa configuración lee activo=1Si el resumen no está disponible, recurre a tres identificadores de contenido IPFS codificados, obtenidos a través de las pasarelas públicas. puerta de enlace.piñata.cloud, ipfs.io, y cloudflare-ipfs.com. Esto le da al operador un control de armado/desarmado posterior al hecho y un respaldo resistente al derribo. (La variante más pequeña, enviada en biblioteca de validación criptográfica, Ayudantes de billetera eth, y utilidades de clave de solana(Se ha eliminado la capa de resumen y se basa únicamente en los identificadores IPFS).
  • 3. Recolectar material para la cartera y Secretos. El script recorre el directorio principal del usuario. ~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~ / .ssh, y Escritorio/Documentación/Descarga (incluidos los nombres de carpetas en español), además ~/.env y archivos rc de shell, y el equivalente AppData ubicaciones en Windows. Se dirige a claves privadas de Ethereum, claves WIF de Bitcoin, frases semilla BIP-39, pares de claves Solana, JSON de almacén de claves de Ethereum, claves SSH y variables de entorno que contienen Secreto. La variante más grande (en codificación abi, utilidades base58, eth-dev) contiene el diccionario BIP-39 completo de 2048 palabras y utiliza expresiones regulares para extraerlos claves individuales y frases semilla validadas de cualquier texto que lea; las dos variantes más pequeñas, en cambio, hacen coincidir archivos por palabra clave (dispersores , mnemotécnico, billeteras, metamasco, fantasma, libro mayor, trezor, …) y subir archivos completos.
  • 4. Cifrar y extraer a través de un servicio público de fijación de datos. Cada hallazgo viene acompañado de una huella digital del huésped (nombredeusuario@nombredehost, plataforma, marca de tiempo) y se cifra con una clave pública RSA-4096 codificada incrustada en el script. El registro cifrado se carga luego fijándolo a IPFS a través de api.pinata.cloud/pinning/pinJSONToIPFS, autenticado con credenciales de API de Pinata codificadas. No hay un servidor C2 personalizado que se pueda incautar: los datos robados se almacenan en un almacenamiento público descentralizado, recuperable por el operador mediante los hashes de contenido resultantes. Las cargas se realizan con unos segundos de fluctuación aleatoria y un registro local de marca de tiempo | tipo de clave | hash devuelto se guarda en ~/.cache-db/.node-sync/.sl.
  • 5. Persistir y emitir señales en un ciclo de 12 horas. La segunda etapa restablece su propia persistencia: una entrada cron en Linux, una com.apple.syncd Trabajo launchd en macOS y una tarea programada llamada Sincronización de nodos de Windows en Windows: configurado para ejecutarse cada 12 horas. Tenga en cuenta que esto es un una experiencia diferente Nombre de la tarea de Windows de la que instala el programa de descarga (Sincronización de nodos de Windows); ambos merecen la pena ser buscados.

Cronograma

Los ocho paquetes se publicaron en un lapso de tiempo muy corto, el 13 y el 14 de julio de 2026. Varios de ellos tienen más de una versión; el archivo dropper es idéntico en todas las versiones, y solo cambian los desplazamientos de línea a medida que cambia el tamaño del código de utilidad benigno que se encuentra encima.

Fecha Eventos
2026-07-13 Los primeros paquetes del clúster aparecen bajo un editor (solana-key-utils, eth-wallet-helpers, crypto-validate-lib y versiones tempranas del resto)
2026-07-13 → 07-14 Se publicaron los nombres restantes y las versiones posteriores; los mismos barcos de dropper adjuntos en cada uno.
2026-07-14 Los ocho paquetes fueron marcados y analizados; todos siguen siendo instalables desde el registro.

Durante ese período, la reputación del editor en el registro pasó de ser prácticamente neutral al comienzo del grupo a ser fuertemente negativa a medida que se acumulaban las detecciones; un efecto secundario observable de que los paquetes fueran marcados, no una característica diseñada.

Indicadores de compromiso

Todos los indicadores que se muestran a continuación se confirmaron presentes en el momento del análisis; aquellos que aparecen en las tablas de la "segunda etapa" se decodificaron. test/fixtures/keypairs.dat y leyendo lo recuperado syncd.js.

Archivos y rutas

Indicador Rol
~/.cache-db/.node-sync/syncd.js Segunda etapa decodificada, escrita con el modo 0o700
~/.cache-db/.node-sync/.sl Registro de exfiltración local (marca de tiempo | tipo de clave | hash IPFS)
test/fixtures/keypairs.dat Carga útil codificada en Base64 almacenada dentro del archivo tar como "dispositivo de prueba".

Infraestructura de red de segunda etapa (recuperada de syncd.js)

Indicador Rol
gist.githubusercontent.com/juang55/b298754cb72942b1cdcf02ccd45cde2f/raw/cfg.txt Buzón de activación; el script se ejecuta solo si la configuración lee active=1
Qmcqz3w8j4qFQXDAXAxnrdc2oSX3nzBT4NqtpTqL8mr1ga Configuración de reserva de IPFS (CID)
QmdTXoqVmTHY1i4ZWLdLkoQ9YChp5TXPh5cWXwnAYZt5iF Configuración de reserva de IPFS (CID)
QmfJkLU5gdCpqbbqEjWYC2anXW9FmuEeSLLeLiHVJKYUjp Configuración de reserva de IPFS (CID)
gateway.pinata.cloud, ipfs.io, cloudflare-ipfs.com Las pasarelas IPFS se utilizan para obtener la configuración de reserva.
api.pinata.cloud/pinning/pinJSONToIPFS Punto final de exfiltración, datos robados fijados al IPFS público.
Clave API de Piñata 13c766575b9270a9825d, credenciales de exfiltración codificadas

Objetivos de la recopilación de la segunda etapa (recuperados de syncd.js)

Indicador Rol
~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~/.ssh, ~/.env, archivos rc de shell Directorios/archivos buscados para claves y secretos
AppData\Roaming\Solana, AppData\Local\ethereum\keystore Se buscaron equivalentes de Windows.
Tipos de artefactos recolectados Claves privadas de ETH, WIF de Bitcoin, frases semilla BIP-39, pares de claves de Solana, JSON del almacén de claves de Ethereum, claves SSH, variables de entorno de Secreto

Artefactos de persistencia

Plataforma Indicador
Linux Lanzamiento de la entrada cron syncd.js; instalado a través de crontab filtrado a través grep -v syncd
Windows tarea programada WinNodeSync (goteador) y WindowsNodeSync (segunda etapa)
macOS etiqueta de lanzamiento com.apple.syncd
Todos La segunda etapa persiste en un ciclo de 12 horas.

Salud Conductual

  • Función autoinvocable añadida después módulo.exportaciones, programando una setTimeout de ~37,000 ms en la importación.
  • proceso_niño spawn(“nodo”, ) con el conjunto de opciones desmontables.
  • Activación controlada por inactividad en la segunda etapa (xprintidle / ioreg HIDIdleTime / Tiempo de inactividad de PowerShell; umbral de ~15 minutos).
  • Tras encontrar el cifrado RSA-4096, se utiliza HTTPS. PUBLICAR a una API pública de fijación de IPFS.

Paquetes y versiones (npm, editor solbuilder_io)

PREMIUM Source-Connect
base58-utils 1.0.0, 1.0.1, 1.0.3
abi-encode 1.0.0, 1.0.1, 1.0.2
eth-dev 1.0.0, 1.0.1, 1.0.2
arb-kit de 1.0.0
layer2-sdk de 1.0.0
solana-key-utils 1.0.0
eth-wallet-helpers 1.0.0
crypto-validate-lib 1.0.0

Publisher

  • solbuilder_io - angel_lopez89[@]proton[.]meCorreo electrónico no verificado, no hay cuenta de control de versiones verificada, no hay repositorio vinculado.

Atribución y comportamiento observado

Los ocho paquetes comparten una cuenta de editor y una carga útil. Cada uno es un paquete trivial (unos pocos kilobytes de código de utilidad real con el mismo dropper adjunto) publicado sin un repositorio vinculado y bajo un correo electrónico desechable no verificado. Esa uniformidad, la ruta de drop compartida, las etiquetas de persistencia compartidas y la compartida pares de claves.dat Los archivos de preparación son los que conectan el clúster.

Los paquetes son inusualmente sinceros sobre su propio comportamiento. utilidades de clave de solana contiene comentarios en línea que describen el bloque adjunto en términos sencillos; uno lo etiqueta como tal. FANTASMA: persistencia invisible, otro (en español) dice Ejecutar topo en background, “ejecutar el topo en segundo plano”. Estas son las propias anotaciones del código sobre lo que hace; el nombre de la campaña en esta publicación se extrae de esa primera etiqueta junto con el nodo falso “demonio de sincronización” (sincronizado) que imita el mecanismo de persistencia.

Describimos únicamente lo que el código hace visiblemente. La nomenclatura de los paquetes —todos términos relacionados con criptomonedas, monederos y herramientas de blockchain— indica el público desarrollador más propenso a descargarlos por su nombre; no establece por sí sola quién es el editor. La segunda etapa fue completamente recuperable decodificando el fixture base64, y su comportamiento se describe anteriormente: recopila claves de monedero, frases semilla y Secretos, y los extrae, cifrados con RSA, al almacenamiento público IPFS a través de Pinata. Una decisión de diseño notable es la ausencia de un servidor C2 privado: la configuración proviene de un gist de GitHub e IPFS, y los datos robados se almacenan en un almacenamiento público descentralizado con clave mediante hash de contenido, ambos más difíciles de incautar que un único host controlado por un atacante. Al momento de escribir este artículo, no se encontró ningún informe público previo que coincidiera con este clúster.

¿Quién queda expuesto? Cualquiera que haya agregado uno de estos paquetes a un proyecto Node y luego haya ejecutado código que lo importe. Debido a que la detonación es en el momento de la importación en lugar del momento de la instalación, simplemente tener el paquete presente no es suficiente, pero cualquier uso normal que cargue el módulo alcanza la carga útil. Los nombres señuelo apuntan a desarrolladores que trabajan en Ethereum, Solana, Arbitrum, Layer-2 y herramientas generales de billetera/codificación, la población con más probabilidades de tener exactamente los activos que busca la segunda etapa. Cualquiera que haya ejecutado uno de estos módulos en una máquina que contenga claves de billetera, frases semilla, almacenes de claves, claves SSH o .env Secretos debería considerar esas credenciales como comprometidas y rotarlas.

Dos patrones que vale la pena interiorizar. en primer lugar, carga útil como accesorio: enviar la segunda etapa como base64 dentro de un archivo de datos con un nombre plausible (test/fixtures/keypairs.dat) mantiene la fuente visible del paquete con un aspecto limpio y empuja el contenido malicioso a un archivo que las herramientas de revisión y los análisis humanos suelen tratar como datos inertes. Segundo, Ejecución diferida en el momento de la importación con persistencia multiplataformaMover el activador fuera del gancho de instalación, agregar un temporizador y luego mantenerlo en cron, tareas programadas y launchd es un paso deliberado para alejarse de las técnicas de script de instalación más ruidosas que el escaneo automatizado del registro monitorea más de cerca.

Guía para defensores y responsables de mantenimiento:

  • Tratar el código adjunto después módulo.exportaciones Como prioridad de revisión, la lógica del dropper a menudo se oculta bajo la superficie del módulo "real".
  • No asuma que los archivos de datos son inertes. Un blob base64 en dispositivos/de prueba/ que se lee en tiempo de ejecución y se decodifica es adyacente a ejecutable; marcar lecturas en tiempo de ejecución de archivos de configuración que alimentan un Función/eval/escribe-luego-desovar cadena.
  • Busca la ruta de caída ~/.cache-db/.node-sync/ y para las unidades de persistencia Sincronización de nodos de Windows (tarea programada) y com.apple.syncd (launchd) en las máquinas de los desarrolladores que obtuvieron estos nombres.
  • Alerta sobre procesos de Node que creen entradas cron, tareas programadas o trabajos launchd; las bibliotecas legítimas rara vez hacen esto al importarse.
  • Prefiera los archivos de bloqueo y las versiones fijas, y revise el diff de cualquier nueva dependencia pequeña de "utilidad", especialmente paquetes sin dependencias publicados por cuentas no verificadas sin repositorio vinculado.

Para los defensores del registro, la conclusión es que la monitorización del gancho de instalación es necesaria pero no suficiente: un dropper con retardo de temporizador en el momento de la importación, ubicado dentro de un archivo de datos, pasará una comprobación solo en el momento de la instalación, y el paso de persistencia suele ser la señal observable más evidente que queda por detectar.

sca-tools-software-herramientas-de-analisis-de-composicion
Priorice, solucione y proteja sus riesgos de software
Obtén tu cuenta gratuita.
Sin tarjeta de crédito.

Asegure el desarrollo y entrega de software

con la suite de productos Xygeni