Cron running a script in a writable path
Arsenal completo de comandos en la cheatsheetUna tarea de cron se ejecuta con la identidad del usuario que la define (lo indica la columna de usuario en /etc/crontab o el dueño del crontab). Si esa tarea lanza un script que vive en un directorio escribible por nuestro usuario actual, o cuyo nombre se resuelve de forma manipulable, podemos sustituir o suplantar ese script y nuestro código correrá con los privilegios del usuario de la tarea.
Enumeración
Leer todos los orígenes de tareas y sus permisos:
cat /etc/crontab
ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/
cat /etc/cron.d/* 2>/dev/null
ls -la /var/spool/cron/crontabs/ 2>/dev/null # crontabs de usuario (root no legible)
systemctl list-timers --all # equivalente moderno: timers de systemdSobre cada script referenciado, comprobar quién puede escribirlo, a él o a su directorio:
ls -la /ruta/al/script.sh
find / -writable -type f 2>/dev/null | grep -vE '^/proc|^/sys'Variantes de abuso
- El script (o su directorio) es escribible. Se añade el payload al final o se renombra el original y se deja uno propio con el mismo nombre. El cron lo ejecuta al siguiente ciclo:
echo 'cp /bin/bash /tmp/rootbash && chmod +xs /tmp/rootbash' >> /ruta/script.sh
# tras el siguiente tick: /tmp/rootbash -p -> euid=0- El cron llama a un binario sin ruta absoluta (
backup.shen vez de/opt/backup.sh): se antepone un directorio escribible alPATHde cron y se planta un binario con ese nombre (secuestro del PATH). - El cron elige "el último" de un patrón (
ls fixer-v* | sort -V | tail -1): basta crear un fichero que gane por orden y meta el payload; encaja con la escritura desde una SQLi con INTO OUTFILE cuando el directorio lo puede escribir el servicio de BD. - Comodín en el comando del cron (
tar czf ... *): ver inyección por comodín.
Es un patrón de pivote entre cuentas de servicio: de mysql a www-data, de www-data a un usuario, aprovechando que cada cron corre como un usuario distinto. El payload típico es una reverse shell o un SUID.
Cómo detectarlo. Los crontabs de /etc/crontab, /etc/cron.d/ y /etc/cron.*/ son legibles, pero el crontab privado de root (/var/spool/cron/crontabs/root) no. Ahí entra pspy: sin privilegios observa los procesos que nacen y mueren, de modo que un cron que se dispara cada minuto aparece en su salida con su ruta y su usuario aunque no puedas leer el crontab (pspy). Visto el script, un ls -la sobre él y su directorio confirma si es escribible. En el lado defensivo, la firma es un script propiedad de root pero en directorio de escritura de grupo/mundo, modificado justo antes de su ejecución programada (auditd sobre open/write del fichero + linaje cron -> sh -> payload).
Defensa. Los scripts que ejecuta cron deben ser propiedad de root (o del usuario de la tarea) y no escribibles por terceros; evitar resolver nombres con comodines sobre directorios compartidos; usar rutas absolutas también dentro del script; y separar las rutas de datos (escribibles por servicios) de las rutas de ejecución.
Máquinas donde se aplica
- CelestialHackTheBox
- ChocolateLoversDockerLabs
- ExfiltratedProving Grounds Practice
- FluProving Grounds Practice
- LaVitaProving Grounds Practice
- NorCDockerLabs
- YummyHackTheBox