Frustración del mantenimiento open source como superficie de ataque

 

El mundo del desarrollo ha evolucionado mucho a lo largo de los últimos años. Cada vez es más frecuente encontrarse en un escenario basado en componentes, módulos y librerías de terceros que ayudan a resolver de forma efectiva ciertas problemáticas comunes de los proyectos de software y que permiten agilizar de forma significativa los tiempos de desarrollo.

Si bien las ventajas de esa reutilización de componentes son evidentes y no deben ponerse en duda, la realidad es que a su vez generan una serie de riesgos que deben ser tenidos en cuenta. Por hacer un símil, se trata de un modelo de responsabilidad compartido frente a vulnerabilidades y potenciales ataques similar al que nos encontramos en el mundo cloud en sus distintas vertientes IaaS, PaaS o SaaS.

El principal problema que nos podemos encontrar en este tipo de escenarios es que si alguno de los módulos que utilizamos en nuestros proyectos de software se ve comprometido, de forma automática nuestro proyecto también se verá afectado por dicha vulnerabilidad. Esto no quiere decir necesariamente que se trate de una vulnerabilidad explotable, pero es un riesgo a evaluar y exige rigor y conocimiento por parte de la organización que utiliza dichos componentes.

Muchos de esos componentes de terceros son proyectos open source mantenidos por una comunidad de tamaños diversos pero en el que, en muchos casos, el peso del desarrollo recae sobre una o dos personas que los mantienen activos y realizan mejoras.

Aquí es donde entra el concepto de frustración en el mantenimiento. Mantener una librería popular requiere mucho trabajo de revisión, evolución y comunicación. Muchas veces los incentivos de hacerlo se diluyen al no haber un retorno claro. Cuando el mantenedor ve que aún siendo una librería muy utilizada el peso del mantenimiento no es compartido con la comunidad que lo usa, la frustración aumenta y jugando con eso es cuando un atacante puede encontrar un campo propicio para ejecutar un ataque.

 

Ataque

La investigación que hoy presentamos surge de un ataque sufrido en septiembre de 2018 por el repositorio de event-stream, una popular librería que cuenta con más de 1,9 millones de descargas semanales y que proporciona funciones de ayuda para el trabajo con streams en aplicaciones basadas en  Node.js.

A pesar de la popularidad de la librería el mantenimiento de la misma recaía principalmente en el dueño del repositorio, como podéis ver en la siguiente gráfica de contribuciones:

A modo de resumen del ataque solamente decir que un atacante, aprovechando el poco mantenimiento de la comunidad consiguió convencer al dueño de que le traspasara la capacidad de publicar tanto en el repositorio y en la plataforma NPM (Node Package Manager). Posteriormente aprovechando estos permisos, modificó el código añadiendo un código malicioso y lo publicó en NPM, consiguiendo así afectar indirectamente a un volumen significativo de proyectos dependientes de esta librería.

Ya existen diversos posts que explican en detalle cómo se realizó este ataque concreto. Se trata de una interesantísima lectura que os recomendamos encarecidamente para obtener el contexto del problema. Os remitimos a uno de ellos (en inglés).

Este ataque tenía un target muy acotado, orientado al robo de wallets de bitcoins gestionados por la plataforma copay-dash que tenía a event-stream como dependencia, pero esto pone de relieve un problema de mayor escala: la gestión de las dependencias de software y las implicaciones que conlleva en términos de seguridad de nuestros proyectos de software, especialmente cuando dependemos de librerías open source.

Este problema de mayor escala es el que queremos analizar en nuestra investigación.

 

Hipótesis

La pregunta que nos hemos hecho para esta investigación es: partiendo de las librerías de las que dependen un mayor número de proyectos en NPM, ¿existe algún caso en el que sus repositorios tengan poco mantenimiento, en el que el contribuidor principal pueda estar frustrado y que por ende sean susceptibles de ser atacadas de la misma forma que event-stream?

Para validar nuestra hipótesis hemos seguido los siguientes pasos:

  • Encontrar las librerías sobre las que recaen más dependencias en NPM
  • Definir las características que definen un bajo mantenimiento de la base de código.
  • Estudiar los resultados y en base a ello extraer unas conclusiones y recomendaciones.

 

Investigación

Hemos partido de las 1000 librerías de las que dependen un mayor número de proyectos de software en la plataforma NPM. Para cada una de estas librerías, hemos extraído con nuestro script en Python ciertas características que nos permiten determinar el nivel de actividad.

Además, para definir el umbral de “bajo mantenimiento” del código hemos marcado las siguientes características:

  • Los repositorios de las librerías han tenido 5 commits o menos en el último año
  • El tamaño de la  comunidad (contribuidores) es menor o igual a 30 personas.
  • El porcentaje de participación de la comunidad en el último año ha sido bajo: para ello hemos medido la contribución de terceros al código base de la librería, sin tener en cuenta las contribuciones del propietario del repositorio.

Esta definición es muy restrictiva, y de hecho la propia librería event-stream no entraría en esa clasificación, ya que cuenta con 16 commits y 34 contribuidores, aunque parte de esos commits forman parte del ataque realizado.

Hemos publicado en Github el repositorio: npm-attack-surface-investigation. En él se encuentra disponible el código Python con el que hemos realizado nuestro análisis, por si resulta de interés para la comunidad.

Esta investigación ha sido realizada desde el Centro TEGRA, un centro de I+D en ciberseguridad situado en Galicia lanzado como una iniciativa conjunta por ElevenPaths, la unidad global de ciberseguridad del grupo Telefónica, y Gradiant el centro tecnológico gallego y con el apoyo de la Xunta de Galicia.

 

Resultados

Los resultados son impactantes: de las 1000 librerías analizadas 250 (25%) tienen un mantenimiento bajo, atendiendo a nuestra definición. Esas 250 librerías acumulan cerca de 700 millones (694M) de descargas semanales, por lo que estamos hablando de proyectos que son ampliamente utilizados a nivel mundial.

De esos 250 repositorios, nos encontramos con 129 librerías (12,9%) que no han tenido ningún commit en el último año y que disponen de más de 330 millones de descargas semanales.

Si a esas 129 librerías que no han tenido ningún  commit en el último año (por lo que no  hemos podido estimar la participación de la comunidad) le añadimos aquéllas marcadas como de bajo manteniendo y que disponen de commits realizados únicamente por el propietario de la librería, el número de librerías vulnerables aumentaría a 168, sumando un total de más de 450 millones de descargas semanales.

En este enlace tenéis más información disponible  para que podáis verificar los resultados obtenidos en nuestra investigación.

 

Conclusiones

Con los resultados obtenidos creemos que nuestra hipótesis puede considerarse validada y que el ataque sufrido por event-stream no será un caso puntual, sino que será una tendencia en alza en los próximos años.

El uso de dependencias externas en el desarrollo de proyectos de software tiene muchas ventajas, pero a su vez implica una serie de riesgos que deben ser identificados y gestionados, especialmente a nivel corporativo, para evitar vernos sorprendidos con la aparición de vulnerabilidades “indirectas” en nuestros proyectos, heredadas de su árbol de dependencias.

Aunque los proyectos de software open source tienen una gran importancia a día de hoy, su mantenimiento es una tarea ardua, ya que en muchos casos la recompensa no es directa ni medible. Si lo unimos además al factor de que estos proyectos están abiertos para que a priori cualquiera que lo desee pueda contribuir, nos encontramos ante un escenario en el que la responsabilidad del mismo queda diluida, lo que facilita aún más que el colectivo sea susceptible de un ataque.

Aunque nuestro análisis se ha centrado exclusivamente en NPM y Node.js, las conclusiones pueden ser extrapolables a otros lenguajes de programación en los que utilicemos librerías open source de terceros.

A continuación damos algunas recomendaciones que nos pueden ayudar a gestionar  estos riesgos desde un perspectiva clásica de ciberseguridad de prevención, detección y respuesta.

 

Prevención

  1. Desde la versión 5.x.x NPM genera un fichero package-lock.json que detalla el conjunto de dependencias específicas de un proyecto en un determinado punto del tiempo. Es importante utilizar este fichero y publicarlo con el código de nuestro proyecto, para asegurar que otros usuarios tengan el mismo árbol de dependencias después de realizar un `npm install` y que no se verán afectados por nuevos patches o minor releases que tengan un potencial carácter malicioso. Esto nos puede ayudar a controlar los riesgos, siempre que en el momento de generación del fichero el árbol de dependencias está saneado.
  2. Antes de incluir una dependencia externa en nuestro software debemos plantearnos si es realmente necesaria y en caso de que sí lo sea, verificar que la librería que vamos a usar tiene una comunidad activa detrás y que cuenta con un mantenimiento activo.

 

Detección

Este es un apartado con mucho potencial de mejora y en el que hay varias iniciativas que merece la pena conocer. Partiendo de la idea de que al menos debemos inventariar las dependencias de nuestros proyectos para poder controlarlas, existen iniciativas open source que tratan de facilitar dicha tarea sobre la base de código de un proyecto.

Ponemos dos ejemplos que acaban de ser presentados por parte de BBVA labs en las XII jornadas STIC del CCN-CERT en Madrid:

  • Patton: un proyecto que utiliza lógica difusa para encontrar vulnerabilidades públicas desde nuestras dependencias o software usado.
  • Deeptracy: un proyecto permite extraer las dependencias de un proyecto.

 

Respuesta

  • Aparte de mantener nuestros proyectos de software actualizados, en muchos casos situarse en la versión más actualizada de nuestras dependencias no supone ningún cambio de código, por lo que es bueno tener una tarea de backlog que nos permita revisar las dependencias actuales y movernos hacia aquellas más recientes.
  • Aunque todos los que hemos trabajado en software sabemos de la dificultad de llevarlo a cabo, es importante destacar que el concepto de comunidad es bidireccional y que si basamos nuestro software, crítico o no, en dependencias de terceros debemos de tratar de contribuir a las comunidades que gestionan dichas partes críticas de nuestros proyectos de software.

Cierre

Las comunidades open source no son la panacea y no debemos verlas desde el punto de vista del consumidor solamente. Participar de forma activa en las comunidades de las que dependen nuestro software es la vía más directa para eliminar la frustración de los mantenedores, controlar el estado real de nuestro código y reducir su potencial superficie de ataque.

 

 


Autores: Juan Elosua Tomé,  director por parte de ElevenPaths del centro I+D en Ciberseguridad TEGRA de Galicia; y David Álvarez Pérez, investigador de ciberseguridad del centro tecnológico Gradiant, partner de ElevenPaths en TEGRA.


 

TEGRA cybersecurity center se enmarca en la unidad mixta de investigación en ciberseguridad IRMAS (Information Rights Management Advanced Systems), que está cofinanciada por la Unión Europea, en el marco del Programa Operativo FEDER Galicia 2014-2020, para promover el desarrollo tecnológico, la innovación y una investigación de calidad.