Transcript
00:00:00Shai Hulud ha vuelto para una cuarta secuela.
00:00:02Esta vez se dirige a paquetes como TanStack,
00:00:04literalmente horas después de que publicara este vídeo sobre Next.js,
00:00:07lo cual fue una sincronización brillante por mi parte.
00:00:08Este es en realidad un ataque masivo a la cadena de suministro de NPM
00:00:11que afecta a algo más que a TanStack.
00:00:13También afectó a paquetes como UiPath, Mistral,
00:00:15y otros 160 paquetes,
00:00:17incluso incluyendo paquetes PyPy como Guardrails.ai.
00:00:20Lo que hace que este sea aún más divertido
00:00:22es que incluía un interruptor de hombre muerto,
00:00:24así que si detectaba que rotabas tus claves robadas,
00:00:26borraba toda tu PC,
00:00:28y también tenía algo de política global incorporada.
00:00:30Así que vamos a sumergirnos.
00:00:36Para esta secuela, El Gusano tiene el mismo objetivo,
00:00:39robar credenciales de máquinas de desarrolladores y runners de CI/CD,
00:00:42luego usar esas credenciales para llegar a más paquetes.
00:00:44Para TanStack, eso significó publicar 84 versiones maliciosas
00:00:47en 42 paquetes de TanStack en solo unos minutos.
00:00:51Ahora, voy a explicar cómo lograron
00:00:52infectar TanStack en primer lugar,
00:00:54pero primero veamos qué hace el malware en sí
00:00:56si instalaras uno de estos paquetes afectados.
00:00:58Dentro de los paquetes maliciosos,
00:00:59encontrarías un nuevo archivo llamado routerinit.js,
00:01:02así como una dependencia opcional inyectada,
00:01:04que conduce a lo que parece
00:01:05un enlace legítimo de GitHub del enrutador TanStack,
00:01:08pero en realidad es un commit huérfano en el fork del atacante.
00:01:10Esta es solo la forma en que GitHub maneja los enlaces de fork,
00:01:13así que la URL en realidad puede parecer
00:01:14que pertenece al proyecto original,
00:01:16aunque el commit sea en realidad de un fork.
00:01:18En ese fork, hay un script de ciclo de vida,
00:01:20prepare, que ejecuta bun run task runner JS,
00:01:22y tiene exit uno al final.
00:01:24Esa es solo una forma inteligente de hacer que la dependencia opcional falle
00:01:27después de que el payload ya se haya ejecutado,
00:01:28así que la instalación continúa como de costumbre,
00:01:30y deja menos rastros obvios en tus registros de instalación.
00:01:33Además, es posible que hayas notado que esto no está ejecutando
00:01:35ese archivo routerinit.js que dije que fue inyectado
00:01:37en los paquetes al principio,
00:01:38pero por ahora, solo piensa en estos dos archivos
00:01:40como si desempeñaran exactamente el mismo papel con nombres diferentes.
00:01:42La versión corta es: cuando instalas esto,
00:01:44va a ejecutar este script.
00:01:46Lo primero que intenta hacer ese script
00:01:47es desacoplarse del flujo de instalación obvio,
00:01:50así que comprobará si ya se está ejecutando
00:01:51en segundo plano, y si no es así,
00:01:53crea una copia desprendida de sí mismo
00:01:54y sale del script principal limpiamente.
00:01:57De esta forma, tus registros de instalación de npm
00:01:58no muestran nada de la salida del script
00:02:00porque el malware ahora se ha separado
00:02:01de ese proceso y se está ejecutando en segundo plano.
00:02:04Después de esto, hace algo realmente inteligente.
00:02:06Escribe copias de sí mismo
00:02:07en tu directorio de ganchos de Claude Code,
00:02:08luego configura tus ajustes de Claude
00:02:10para ejecutar este gancho cada vez que uses Claude Code
00:02:12en ese proyecto.
00:02:13De esta manera, puede sobrevivir después de la instalación original
00:02:16y seguir disparándose cada vez que
00:02:17abras Claude Code en ese proyecto.
00:02:20De hecho, hace lo mismo con el ejecutor de tareas de VS Code,
00:02:22duplicándose ahí también,
00:02:23así que si usas las funciones de ejecución automática de espacios de trabajo de VS Code,
00:02:26tienes exactamente el mismo problema.
00:02:28Incluso configura un servicio a nivel de SO
00:02:29llamado Monitor de Tokens de GitHub,
00:02:31pero volveremos a eso
00:02:32porque ese es absolutamente diabólico.
00:02:34También es bastante diabólico
00:02:35que aún no te hayas suscrito.
00:02:37Lo siguiente que hace el payload
00:02:38es ponerse a trabajar robando tus credenciales,
00:02:40e intenta de todo.
00:02:41En GitHub Actions, busca credenciales
00:02:43y secretos en el entorno del runner.
00:02:45Más específicamente, analizando la memoria
00:02:47del proceso del worker del runner
00:02:48de GitHub Actions para obtener tus secretos de flujo de trabajo
00:02:50que incluyen secretos enmascarados,
00:02:52e incluso inserta un flujo de trabajo de GitHub falso que parece CodeQL
00:02:55que serializa los secretos de tu repositorio
00:02:57y los exfiltra más tarde.
00:02:58También busca secretos de AWS,
00:03:00primero yendo tras tus variables de entorno
00:03:02y archivos de configuración locales,
00:03:03pero luego también va tras los servicios de metadatos de AWS
00:03:06como IMDS v2 y los metadatos de tareas de ECS.
00:03:09Para Kubernetes, roba tokens de cuentas de servicio
00:03:11y certificados, lo que le permite acceso a la API dentro del clúster
00:03:14a cualquier privilegio de control de acceso basado en roles
00:03:17que tuviera la cuenta de servicio de ese pod,
00:03:19que en clústeres mal configurados
00:03:21puede ser extremadamente amplio,
00:03:22a veces efectivamente administrador.
00:03:24Y para empeorar aún más eso,
00:03:25también va tras HashiCorp Vault,
00:03:27reuniendo todas tus variables de entorno y tokens
00:03:29relacionados con Vault,
00:03:30luego usa cualquier acceso a Kubernetes que tenga
00:03:32para recuperar todos tus secretos gestionados por Vault.
00:03:34Y todo eso es solo lo que hace
00:03:35a tus despliegues de CI.
00:03:37Si está en tu estación de trabajo,
00:03:38va tras todas tus claves SSH,
00:03:39tus credenciales de NPM,
00:03:41tus credenciales de Git,
00:03:42el historial del shell,
00:03:43credenciales de proveedores de la nube,
00:03:44claves criptográficas,
00:03:45Signal,
00:03:45Slack,
00:03:45y archivos de Discord.
00:03:46Y además de todo eso,
00:03:47extrae el historial de sesiones de Claude Code.
00:03:49Así que si alguna vez le has dado credenciales a Claude
00:03:51o has dejado que lea archivos que contienen credenciales,
00:03:53tiene acceso a esos también.
00:03:55Así que sí, como dije,
00:03:56estaban detrás de absolutamente todo
00:03:57lo que podían tener en sus manos,
00:03:58y luego exfiltrarían estos datos
00:04:00a través de la red de mensajería Session.
00:04:02Y como respaldo,
00:04:02también dejaron caer estos datos robados
00:04:04en repositorios de GitHub.
00:04:05Y siguiendo la temática de todos sus ataques,
00:04:07estas ramas tienen nombres de referencias de Dune.
00:04:09Así que tiene tus credenciales.
00:04:11No puede ponerse peor, ¿verdad?
00:04:12Bueno, sí.
00:04:13Sí, puede.
00:04:14Además de todo eso,
00:04:15si recuerdas ese servicio
00:04:16que dije que configura en tu máquina,
00:04:18bueno, ese monitorea tus tokens de GitHub
00:04:19y sigue re-exfiltrándolos.
00:04:21Pero también cada minuto,
00:04:22verifica si el token sigue siendo válido.
00:04:24Y si no lo es,
00:04:25ejecuta RMRF en tu directorio de usuario,
00:04:27borrándolo todo.
00:04:28También intenta crear un token de NPM
00:04:30con tus credenciales,
00:04:31con la descripción,
00:04:32si revocas este token,
00:04:33borraremos la computadora del propietario,
00:04:35dando a entender que hace lo mismo
00:04:36también para los tokens de NPM.
00:04:38Así que si revocas estos tokens
00:04:39antes de aislar tu máquina
00:04:40y eliminar ese proceso en segundo plano,
00:04:42el payload puede autodestruir tu PC,
00:04:44lo cual es simplemente absolutamente diabólico.
00:04:46Y como nota al margen aquí,
00:04:47la variante de Python de este ataque
00:04:48hace más o menos lo mismo,
00:04:49pero también incluye una verificación
00:04:51para ver si el idioma de tu máquina es ruso.
00:04:53Si lo es,
00:04:53simplemente se detiene.
00:04:54Y si tu máquina parece ser
00:04:55de Israel o Irán,
00:04:56genera un número aleatorio
00:04:58entre 1 y 6.
00:04:59Y si ese número es 2,
00:05:00ejecuta un comando de borrado destructivo
00:05:01e intenta reproducir a todo volumen
00:05:03un MP3.
00:05:04Tristemente,
00:05:05no pude averiguar
00:05:05cuál es ese MP3.
00:05:07De todos modos,
00:05:07ahora que ha hecho todo eso,
00:05:08lo peor aún está por llegar
00:05:09porque eso fue solo la etapa 1.
00:05:11La etapa 2 es la autopropagación
00:05:13y esa es la parte más peligrosa
00:05:15de este ataque.
00:05:16Primero,
00:05:16buscará en tu máquina
00:05:17algún token de NPM válido
00:05:19donde pueda publicar
00:05:19sin autenticación de dos factores.
00:05:21Y si encuentra uno,
00:05:22escaneará todos los paquetes
00:05:24a los que esa cuenta tenga acceso,
00:05:26luego usará esas credenciales
00:05:26para añadirse a esos paquetes
00:05:28y publicar nuevas versiones infectadas.
00:05:30Eso es obviamente bastante malo,
00:05:32pero probablemente tampoco deberías
00:05:33tener tokens publicados
00:05:33dando vueltas
00:05:34que pueden saltarse
00:05:35la autenticación de dos factores.
00:05:36Así que la versión mucho más aterradora de esto
00:05:38es lo que sucede
00:05:39cuando se ejecuta dentro de tu CI/CD.
00:05:41Porque en CI,
00:05:42el atacante no necesita
00:05:43un token de NPM de larga duración
00:05:44porque las buenas configuraciones
00:05:45a menudo dependen de OIDC,
00:05:47que se supone que es más seguro.
00:05:48Esencialmente,
00:05:49en lugar de almacenar
00:05:50un token de NPM como un secreto,
00:05:51GitHub Actions le prueba a NPM:
00:05:53oye,
00:05:53soy este repositorio
00:05:54ejecutando este flujo de trabajo
00:05:55en esta rama,
00:05:56y NPM entonces le da
00:05:57un token de publicación de corta duración.
00:05:59El problema con esto, sin embargo,
00:06:00es que si el script obtiene acceso
00:06:01a un entorno de confianza de GitHub Actions,
00:06:03puede ponerse en el mismo lugar
00:06:04que un editor legítimo.
00:06:06Así que el malware puede usar
00:06:07el entorno relacionado con OIDC
00:06:08que GitHub expone al trabajo
00:06:10para solicitar un token JWT OIDC
00:06:12desde el punto final de tokens de GitHub,
00:06:14luego intercambia ese token JWT
00:06:16con NPM
00:06:17por un token de publicación de corta duración
00:06:18a través del sistema de publicación
00:06:19de confianza de NPM,
00:06:20y ahora puede publicar
00:06:22sin tener que robar nunca
00:06:22un token permanente de NPM
00:06:24y parecer completamente legítimo.
00:06:26En este caso,
00:06:26el malware incluye una copia
00:06:27de ese archivo router init.js
00:06:29en la tabla del paquete,
00:06:30luego agrega la dependencia
00:06:31opcional maliciosa,
00:06:32luego lo publica todo
00:06:33como la última etiqueta
00:06:34para ese paquete,
00:06:35así que cuando alguien
00:06:35o alguna tubería CI/CD
00:06:37instala esos paquetes,
00:06:38el ciclo comienza de nuevo,
00:06:40esparciéndose lo más lejos
00:06:40que pueda llegar.
00:06:42Así que todo eso
00:06:42es bastante loco, ¿verdad?
00:06:43Pero ahora enfoquémonos
00:06:44en el paciente cero,
00:06:46TanStack.
00:06:46¿Cómo se infectaron
00:06:47en primer lugar?
00:06:48Bueno,
00:06:49según su propio post-mortem,
00:06:50el atacante abusó
00:06:51de esa tubería de GitHub Actions.
00:06:53Comenzaron el día
00:06:53antes de que los paquetes maliciosos
00:06:54fueran realmente publicados,
00:06:56cuando crearon una bifurcación
00:06:57de TanStack router,
00:06:58pero en realidad lo renombraron
00:06:59como configuración
00:06:59para intentar hacerlo más difícil
00:07:01de encontrar si estabas buscando
00:07:02a través de los nombres de bifurcación obvios.
00:07:04Luego agregaron
00:07:04una confirmación maliciosa
00:07:05a esta bifurcación,
00:07:06que falsificaron como autor
00:07:07a Claude,
00:07:07y tenía un mensaje de confirmación
00:07:08que estaba precedido
00:07:09por skip CI,
00:07:10para que no ejecutara inmediatamente
00:07:11el CI en un evento de envío.
00:07:13Al día siguiente,
00:07:13luego abrieron una PR
00:07:14contra TanStack router
00:07:15llamado Work in Progress
00:07:16Simplify History Build.
00:07:18Y aquí es donde
00:07:18ocurre el ataque real.
00:07:20El resumen es que
00:07:21TanStack tenía un flujo de trabajo
00:07:22de GitHub Actions de tamaño de paquete
00:07:23que usaba pull request target,
00:07:25y eso es notable
00:07:26porque pull request target
00:07:27en realidad se ejecuta
00:07:28en el contexto de seguridad
00:07:29del repositorio base,
00:07:30no en la bifurcación.
00:07:31Eso significa que tiene acceso
00:07:32al ámbito de caché del repositorio base
00:07:33y a su token de GitHub.
00:07:35Así que este flujo de trabajo
00:07:35revisó la PR,
00:07:36instaló sus dependencias,
00:07:38y ejecutó una compilación de referencia.
00:07:39El problema, sin embargo,
00:07:40es que esa bifurcación contenía
00:07:40código malicioso.
00:07:41En este caso,
00:07:42era un script de configuración V
00:07:43que envenenó el
00:07:44almacén de paquetes PMPM
00:07:45bajo la clave de caché exacta
00:07:47que la acción de lanzamiento
00:07:48usaría más tarde.
00:07:49De hecho, pre-calcularon
00:07:50esto desde el archivo
00:07:51de bloqueo público de PMPM
00:07:52usando la misma fórmula exacta
00:07:54que también usa el flujo de trabajo.
00:07:56Una vez que esa caché envenenada
00:07:57se guardó,
00:07:57de hecho, restablecieron
00:07:58esa rama
00:07:59para que coincida con la rama
00:07:59principal actual,
00:08:00así que la PR visible
00:08:01parecía un archivo cero
00:08:02sin operaciones,
00:08:03y luego cerraron esa PR
00:08:04y eliminaron
00:08:05la rama maliciosa.
00:08:06Así que desde fuera,
00:08:07parece como si
00:08:07absolutamente nada
00:08:08hubiera pasado,
00:08:09pero han envenenado
00:08:10la caché de esa acción de GitHub.
00:08:11Esto significa que
00:08:12ocho horas más tarde,
00:08:13cuando un mantenedor normal
00:08:14fusionó una PR no relacionada
00:08:15a la principal,
00:08:16se activó el flujo de trabajo
00:08:17de lanzamiento de TanStack,
00:08:18que restauró la
00:08:19caché envenenada de PMPM,
00:08:20y ahora el código controlado por el atacante
00:08:22se estaba ejecutando dentro
00:08:23de esa acción de lanzamiento.
00:08:24Entonces usó la misma lógica
00:08:25con OIDC
00:08:26para obtener un token de publicación de NPM,
00:08:28y logró publicar
00:08:2984 versiones de sí mismo
00:08:30a través de 42 paquetes Tanstack,
00:08:32y ni siquiera necesitó
00:08:33llegar al paso
00:08:34de publicar paquete
00:08:35de la acción.
00:08:36Curiosamente,
00:08:36la acción realmente falló
00:08:37porque algunas pruebas fallaron,
00:08:39así que nunca llegó a ese paso,
00:08:40pero el código malicioso se ejecutó
00:08:41y publicó todas ellas
00:08:43de todos modos.
00:08:43Así que el atacante logró
00:08:44encadenar tres límites de confianza.
00:08:46Primero,
00:08:47el código PR de la bifurcación
00:08:47pudo envenenar
00:08:48la caché del repositorio base,
00:08:49luego esa caché del repositorio base
00:08:51se restauró dentro
00:08:52del flujo de trabajo de lanzamiento real,
00:08:53luego el flujo de trabajo de lanzamiento real
00:08:54tiene permisos OIDC,
00:08:56que se convierten en
00:08:57acceso de publicación de NPM,
00:08:58así que pueden publicar
00:08:59lo que parece ser
00:08:59paquetes completamente legítimos.
00:09:01Y eso es lo que creo
00:09:02que se está volviendo realmente aterrador
00:09:03sobre los ataques a la cadena de suministro.
00:09:05Se están alejando
00:09:05de robar
00:09:06el token de un mantenedor
00:09:07a abusar
00:09:08del sistema CI/CD completo en sí,
00:09:10y eso significa
00:09:11que todas nuestras señales de confianza
00:09:12están empezando a trabajar
00:09:13para el atacante.
00:09:14Este era un paquete firmado
00:09:15con procedencia válida
00:09:16publicado por un flujo de trabajo real.
00:09:18Así que ahí lo tienen,
00:09:19eso es ShaiHalud4,
00:09:20y si quieres comprobar
00:09:21si has sido comprometido
00:09:21por alguno de estos paquetes,
00:09:23dejaré enlaces
00:09:23a publicaciones de blog a continuación,
00:09:25que cubrirán
00:09:25cómo puedes averiguarlo
00:09:26y qué puedes hacer
00:09:27si has instalado
00:09:28uno de estos.
00:09:29Déjame saber en los comentarios
00:09:30qué piensas
00:09:30acerca de todo esto
00:09:31y el ecosistema NPM,
00:09:33mientras estás allí abajo,
00:09:33suscríbete,
00:09:34y como siempre,
00:09:34nos vemos en la próxima.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video