¿Qué es una puerta trasera? Creemos una con Node.js
19 de marzo de 2020
0 minutos de lecturaUna puerta trasera en nuestro código capaz de ejecutar una inyección en el sistema operativo es uno de los escenarios más aterradores. Actualmente, npm tiene más de 1,2 millones de paquetes públicos disponibles. En los últimos tres años, nuestras dependencias se han convertido en el objetivo perfecto para los ciberdelincuentes. Hemos visto muchos ataques nuevos en acción, como el ataque de typosquatting o el incidente deevent-stream, que confirman que nuestro ecosistema puede ser muy frágil si no construimos una comunidad más sólida. En esta publicación te mostraré cómo podemos combinar algunas técnicas y terminar con una puerta trasera maliciosa en el ecosistema.
¿Qué es una puerta trasera?
En el mundo de la ciberseguridad, una puerta trasera es cualquier método que permite a usuarios autorizados y no autorizados eludir las medidas de seguridad habituales y obtener acceso de alto nivel (también conocido como acceso root) a un sistema informático, una red o una aplicación de software. Una vez dentro, los ciberdelincuentes pueden usar una puerta trasera para robar datos personales y financieros, instalar malware adicional y secuestrar dispositivos.
Toda puerta trasera tiene dos componentes principales: el malware que se inyecta y ejecuta en la víctima, y un canal de comunicación abierto que permite al atacante enviar comandos y controlar el host remoto.
Una vez instalada una puerta trasera, hay que enviar comandos específicos para que se ejecuten en la máquina objetivo. Esos comandos pueden exfiltrar información confidencial, como variables de entorno o datos de bases de datos. Además, pueden alterar otros procesos en la máquina o la red, según los permisos de ejecución que tenga nuestra aplicación Node infectada.
Para crear una versión simplificada de este ataque, usaremos la biblioteca principal child_process para ejecutar código y un servidor HTTP como canal de comunicación. En este caso, sugiero usar Express, ya que es el framework más extendido, pero se puede adaptar a cualquier otro framework.
¡No olvides analizar tus proyectos para detectar puertas traseras conocidas!
¿Cómo puede ayudarnos child_process?
Podemos usar el módulo principal child_process de Node.js para ejecutar procesos secundarios. La idea es ejecutar un comando (a esta entrada la llamamos stdin), como pwd o ping snyk.io, y luego integrar la respuesta (a esta salida la llamamos stdout) y los posibles errores (a estos errores los llamamos stderr) en el programa principal.
Hay varias formas de ejecutar procesos secundarios. Para este ataque, la más sencilla es exec, que ejecuta una función de retorno con stdout y stderr una vez que el proceso termina, como cat passwords.txt. Ten en cuenta que exec no es la mejor opción para tareas largas, como ping snyk.io.
¿Cómo podemos conectar este exec al servidor HTTP?
Desarrollé un paquete de middleware sencillo e inocente que redirigirá a cualquier persona que no use Chrome a otra URL, como browsehappy.com. Incluiré la carga maliciosa en el middleware.
El código esperado del paquete sería algo así:
Así que el único requisito para la víctima es instalar la biblioteca browser-redirect y agregarla a la aplicación Express como un middleware normal:
Ten en cuenta que, en este caso, tu aplicación sigue siendo vulnerable aunque uses Helmet.
Cómo implementar la carga maliciosa
La implementación es muy sencilla:
¿Cómo funciona la puerta trasera? Debes comprender tres desafíos:
Necesitas una forma de autenticarte para evitar que otros ciberdelincuentes usen tus propias puertas traseras. En este caso, usamos un hash MD5 (la palabra
p@ssw0rd1234genera este hash:c4fbb68607bcbb25407e0362dab0b2ea). Debes incluir este hash como valor de tu encabezadoknock_kockpara validar la autenticación.Necesitas una forma de identificar los servidores que contienen el código malicioso. No queríamos recopilar métricas, así que agregamos un encabezado adicional a la respuesta del servidor:
Content-Sec-Policy. Parece muy similar aContent-security-policy, pero no es lo mismo. De nuevo, estamos aprovechando el ataque de typosquatting. Ahora podemos encontrar nuestros objetivos en Shodan con esta consulta:/search?query=Content-Sec-Policy%3A+default-src+%27self%27Podemos usar el parámetro de consulta ?cmd para ejecutar consultas en el servidor infectado, en cualquier ruta; por ejemplo,
victim.com/?cmd=whoamio?cmd=cat .env— y recibiremos toda la información en formato JSON.
Ahora que la carga maliciosa está lista, hay que idear una forma inteligente de distribuir el paquete malicioso.
Vectores de propagación
El primer paso es subir el paquete malicioso a Internet. Acabo de publicar el paquete malicioso en npm con npm install browser-redirect@1.0.2. Sin embargo, en GitHub no se puede ver el código malicioso: consulta Master Branch y release 1.0.2. Esto se debe a que npm no compara el contenido con GitHub ni con ningún otro repositorio de control de código fuente.
Por ahora, las probabilidades de propagar esta puerta trasera por el ecosistema son muy bajas, ya que otros deben promocionar e instalar el paquete malicioso.
Otra forma de propagarla es incluir el módulo malicioso como dependencia de otros paquetes. Si el atacante tiene permisos de publicación en otros paquetes clave, puede publicar una nueva versión que incluya directamente una dependencia con el paquete malicioso (consulta el análisis posterior de event-stream). También puede intentar contribuir un pull request a un proyecto con recursos maliciosos en el archivo de bloqueo, como se describió en la investigación sobre seguridad de archivos de bloqueo: dependencia en el package-lock.
Otro factor importante que hay que tener en cuenta es si los atacantes pueden acceder a las credenciales (usuario y contraseña) de algún responsable de mantenimiento relevante. Si es así, pueden implementar fácilmente nuevas versiones de paquetes populares, como ocurrió en el pasado con eslint.
Aunque el responsable de mantenimiento use 2FA para autenticarse y publicar, sigue habiendo riesgos. Cuando elige usar CI para implementar nuevas versiones, debe desactivar la 2FA para las publicaciones. Por eso, si el atacante puede robar un token npm válido para CI (por ejemplo, de registros compartidos o accesibles públicamente, filtraciones de datos, etc.), puede implementar nuevas versiones con código malicioso.
Ten en cuenta que npm ha lanzado una nueva API (en beta privada) que muestra si el paquete se publicó desde una dirección IP de TOR y si se usó 2FA.
Además, los atacantes pueden adaptar la carga maliciosa para que funcione como un script de preinstalación o posinstalación en cualquier paquete npm. De forma predeterminada, los paquetes npm tienen un hook de ciclo de vida que permite ejecutar código en tu máquina en distintos momentos. Por ejemplo, el paquete de pruebas de navegadores Puppeteer usa este hook de ciclo de vida para instalar Chromium en la máquina host. Ryan Dahl ya explicó estas fallas de seguridad en JSConf EU 2018. Es necesario proteger Node.js para prevenir este vector y muchos otros.
Recuerda que:
El 78 % de las vulnerabilidades se encuentra en dependencias indirectas, lo que dificulta su corrección
Las vulnerabilidades en bibliotecas de aplicaciones aumentaron un 88 % en dos años
El 81 % cree que los desarrolladores deberían hacerse cargo de la seguridad, pero no cuentan con las herramientas adecuadas
Fuente: El estado de la seguridad del código abierto: 2019. Consulta nuestro nuevo informe sobre el estado de la seguridad del código abierto : 2020
¿Cómo mitigar este ataque?
No siempre es fácil mantener nuestras dependencias bajo control, pero aquí tienes algunos consejos útiles:
Usa bibliotecas conocidas y con buen mantenimiento.
Participa en la comunidad y ayuda a los responsables de mantenimiento contribuyendo con código o brindando apoyo financiero a los proyectos y a quienes los mantienen.
Usa NQP para evaluar los paquetes nuevos de tu proyecto.
Usa Snyk para estar al tanto de las nuevas vulnerabilidades y monitorear tus proyectos.
Revisa el código de tus dependencias desde npm, no solo desde GitHub, Bitbucket u otros sistemas de control de versiones.
Analiza tus proyectos para detectar puertas traseras conocidas.
Lecciones aprendidas de incidentes anteriores
Crea hoy una cuenta gratuita de Snyk y analiza tus proyectos para detectar puertas traseras conocidas.
Comienza con Capture the Flag
Aprende a resolver desafíos de Capture the Flag con nuestro taller virtual 101 a pedido.
