Crónica de la inyección de código malicioso a biblioteca de JavaScript

El 26 de noviembre se dio a conocer que una biblioteca de JavaScript muy utilizada hacía referencia a un código malicioso cuyo objetivo es obtener el control de la cartera de criptomonedas de los usuarios.

A continuación compartimos una breve crónica de cómo se dio el ataque:

En 2011 Dominic Tarr (@dominictarr) crea Event Stream (event-stream), una biblioteca JavaScript que provee funciones que facilitan trabajar con streams de datos en Node. Dominic publica Event Stream en el repositorio de paquetes npm para hacerla disponible a la comunidad y la mantiene durante algunos años.

Después de unos años, Dominic deja de prestarle atención a event-stream y no la actualizaba desde 2016. A pesar de ello, era muy utilizada (2 millones de descargas semanales) ya que varias herramientas populares (como el monitor de aplicaciones Nodemon) dependían de ella.

En verano del 2018, Dominic recibe un correo del usuario right9ctrl ofreciéndose a hacerse cargo del mantenimiento de event-stream. Dado que Dominic ya no tenía tiempo de ni ganas de seguirla manteniendo, cede el control completo a right9ctrl.

El 5 de septiembre, right9ctrl publica una nueva versión patch (3.3.5) de event-stream agregando una dependencia a una nueva biblioteca llamada flatmap-stream. Todo aparentemente estaba bien, y el cambio parecía más que nada una refatorización para mejorar la organización. 

El 16 de septiembre, right9ctrl publica una nueva versión mayor de event-stream (4.0.0) que ya no tiene la dependencia a flatmap-stream. Esto es un mecanismo efectivo de "maquillaje" ya que aunque la última versión (4.0.0) está limpia, como es una versión mayor los paquetes con dependencia no hacen upgrade automáticamente y siguen utilizando la versión 3.3.5.

El 5 de octubre, un usuario distinto (hugeglass) publica una actualización a flatmap-stream con código minificado. El código minificado incluye un snippet de código ofuscado. Conforme las aplicaciones que utilizan event-stream se actualizaron, recibieron automáticamente este código malicioso.

El código se mantiene ocioso, y solo se activa cuando es utilizado en el contexto de la app Copay, que es la cartera de criptomonedas de la plataforma BitPay. Copay tiene (tenía) dependencia a event-stream. Al ser activado, el código obtiene información de la cartera, incluyendo sus llaves privadas y la envía a un servidor remoto (para que el atacante pueda usarla para vaciar la cartera).

A finales de octubre se publica una nueva versión LTS de Node (10), que por fortuna depreca un API utilizado por el código malicioso. Esto hace que Nodemon se de cuenta que hay un problema de dependencias a código deprecado en flatmap-stream. Todavía no se tiene idea de que esto sea código malicioso, así que simplemente se pone a flatmap-stream como dependencia transitiva y se levanta un issue pidiendo al desarrollador que corrija su código para no usar el API deprecado.

El 20 de noviembre se comienza a investigar qué hace flatmap-stream, pero no está sencillo descifrar el código. Se cuestiona a dominictarr, quien contesta que cedió el control y ya ni siquiera tiene acceso para cambiar el repo.

El 26 de noviembre se logra descifrar el código y se avisa a la comunidad para corregir el problema. BitPay corrige su app y avisa a sus usuarios, pero el daño ya está hecho (no se ha dado a conocer el impacto).

Es interesante ver cómo se dio este ataque y lo que el atacante hizo para esconder sus intenciones. El único error que cometió fue usar una API a punto de ser deprecada, de no haber sido así la comunidad seguiría sin enterarse del ataque. Esto nos lleva a cuestionar si habrá ataques similares activos sin detectar (es altamente probable que sí). 

Este suceso ha revivido varias discusiones con la intención de evitar que sucedan casos como este. Entre los puntos abordados destacan:

  • Cómo cómpensar a los desarrolladores open source, para que puedan seguir manteniendo el software que crean y donan a la comunidad.
  • Qué pasos/controles se deben llevar a cabo cuando un desarrollador pasa control de su software a alguien más.
  • Cómo mejorar el control y seguridad del código disponible en repositorios como npm. Por ejemplo, una de las peticiones es que no se permita subir código minificado/ofuscado.

Algunos de estos puntos han sido abordados en un hilo de discusión en el repositorio de event-stream en Github.