Un servidor Linux puede tener el kernel actualizado, SSH endurecido, firewall, EDR y una política de parches razonable y seguir ofreciendo una vía sencilla para escalar privilegios. El problema puede estar en algo tan cotidiano como un SUID olvidado, un script modificable por el usuario equivocado, una ACL heredada o acceso al socket de Docker. Los permisos siguen siendo una de las superficies de ataque que un administrador debería revisar periódicamente.
Las claves de la auditoría de permisos Linux en 20 segundos
- SUID, SGID y Linux capabilities pueden otorgar privilegios que pasan desapercibidos en una revisión superficial.
- Cron, systemd y scripts ejecutados por root son peligrosos si usuarios sin privilegios pueden modificarlos.
- Las ACL pueden conceder accesos que no aparecen claramente en los bits tradicionales de
ls -l. /var/run/docker.socky determinados grupos deben tratarse prácticamente como accesos administrativos.- Mantener baselines permite detectar cambios de permisos después de actualizaciones, instalaciones o incidentes.
La dificultad no está en entender rwx. Está en descubrir cadenas de permisos. Un archivo aparentemente irrelevante puede ser modificable por un usuario y ejecutado cinco minutos después por un servicio con UID 0. Una biblioteca puede encontrarse en un directorio escribible. Una ACL puede conceder acceso aunque chmod parezca correcto.
Para un sysadmin, por tanto, la pregunta útil no es únicamente qué permisos tiene un archivo. También importa quién controla cada elemento de la ruta y con qué identidad termina utilizándose.
1. SUID y SGID: empezar por los privilegios evidentes
SUID (Set User ID) y SGID (Set Group ID) permiten ejecutar determinados binarios con los privilegios asociados a su propietario o grupo.
El inventario básico debería formar parte de cualquier auditoría:
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f \
-exec ls -la {} \; 2>/dev/nullLenguaje del código: JavaScript (javascript)
El resultado por sí mismo no identifica vulnerabilidades. Lo interesante es compararlo con el estado conocido del servidor:
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f \
2>/dev/null | sort > suid-baseline.txtLenguaje del código: JavaScript (javascript)
Después de una actualización:
diff suid-baseline.txt \
<(find / -xdev \( -perm -4000 -o -perm -2000 \) \
-type f 2>/dev/null | sort)Lenguaje del código: JavaScript (javascript)
Un SUID nuevo no implica un compromiso, pero debería poder asociarse a un paquete y justificar su necesidad.
2. World-writable: buscar dónde puede escribir cualquiera
Los permisos 777 son fáciles de detectar. Más interesante resulta averiguar si un usuario sin privilegios puede modificar algo que posteriormente consumirá root.
Para archivos:
find / -xdev -type f -perm -002 2>/dev/nullLenguaje del código: JavaScript (javascript)
Para directorios escribibles por todos y sin sticky bit:
find / -xdev -type d -perm -002 ! -perm -1000 2>/dev/nullLenguaje del código: JavaScript (javascript)
Un /tmp con 1777 es normal. Un /opt/company/scripts con permisos equivalentes merece bastante más atención si desde allí se ejecutan automatizaciones administrativas.
No conviene corregir resultados masivamente con chmod. Primero hay que conocer qué servicio utiliza cada ruta.
3. /etc/shadow, credenciales y secretos de aplicaciones
Los permisos de /etc/passwd, /etc/shadow, /etc/group y /etc/gshadow proporcionan una comprobación básica:
stat -c '%A %a %U:%G %n' \
/etc/passwd /etc/shadow /etc/group /etc/gshadowLenguaje del código: JavaScript (javascript)
Las configuraciones concretas dependen de la distribución. /etc/shadow, por ejemplo, puede encontrarse legítimamente como 640 root:shadow o bajo otra configuración restrictiva.
El mismo control debería extenderse a secretos menos evidentes:
.env
config.yml
database.ini
credentials.json
*.pem
*.keyLenguaje del código: CSS (css)
Un servidor puede proteger correctamente /etc/shadow mientras mantiene una contraseña de PostgreSQL o una clave de API legible por todos dentro de /opt/app.
4. SSH: no basta con proteger id_ed25519
La revisión de SSH debería incluir .ssh, las claves privadas y authorized_keys.
Una configuración habitual sería:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
Pero el propietario importa tanto como el modo:
stat -c '%A %a %U:%G %n' \
~/.ssh ~/.ssh/authorized_keys ~/.ssh/id_ed25519Lenguaje del código: JavaScript (javascript)
Un authorized_keys modificable por otra cuenta permite alterar quién puede autenticarse como ese usuario.
Además, una auditoría debería revisar el contenido. Una clave con permisos perfectos continúa siendo un problema si pertenece a un proveedor que dejó de trabajar con la organización hace dos años.
5. Sudoers: cuando el mínimo privilegio acaba convirtiéndose en root
Las reglas de sudo merecen especial atención porque una configuración aparentemente restringida puede permitir escapar hacia una shell privilegiada.
El caso obvio es:
user ALL=(ALL) NOPASSWD: ALL
Pero también deben examinarse reglas que autorizan intérpretes, editores o comandos con argumentos demasiado flexibles.
Primero:
sudo visudo -c
Después puede realizarse una búsqueda inicial:
grep -rP '(NOPASSWD|ALL)' \
/etc/sudoers /etc/sudoers.d/ 2>/dev/nullLenguaje del código: JavaScript (javascript)
No todo resultado es inseguro. El administrador debe determinar qué puede conseguir realmente el usuario utilizando cada comando autorizado, no limitarse a leer su nombre.
6. Cron y systemd: root ejecutando código controlado por otro usuario
Este patrón merece una revisión específica porque puede crear una vía directa de escalada.
Para cron:
crontab -l -u root
cat /etc/crontab /etc/cron.d/* 2>/dev/null
Para temporizadores:
systemctl list-timers --allLenguaje del código: PHP (php)
Y para buscar unidades modificables por grupo u otros:
find /etc/systemd/system /usr/lib/systemd/system \
-type f -name '*.service' -perm -022 2>/dev/nullLenguaje del código: JavaScript (javascript)
La revisión no termina en el .service.
Si aparece:
ExecStart=/opt/company/bin/backup.shLenguaje del código: JavaScript (javascript)
hay que comprobar backup.sh, su propietario y los permisos de sus directorios padre.
Una unidad protegida que termina ejecutando un script modificable por un usuario normal sigue teniendo un problema.
7. Linux capabilities: privilegios que ls -l no enseña
SUID ya no es la única forma de conceder capacidades privilegiadas a un ejecutable.
Linux permite dividir determinados privilegios mediante capabilities. El inventario puede obtenerse con:
getcap -r / 2>/dev/nullLenguaje del código: JavaScript (javascript)
Entre las capacidades que requieren una revisión especialmente cuidadosa están cap_setuid, cap_dac_override, cap_sys_ptrace, cap_net_admin y la extensa cap_sys_admin.
También aquí funciona bien un baseline:
getcap -r / 2>/dev/null | sort > capabilities-baseline.txtLenguaje del código: JavaScript (javascript)
La pregunta no debería ser únicamente si una capability es peligrosa, sino por qué ese ejecutable concreto la necesita.
8. Docker socket y grupos con privilegios indirectos
En instalaciones Docker convencionales, proporcionar acceso a:
/var/run/docker.sockLenguaje del código: JavaScript (javascript)
debe considerarse una decisión de seguridad importante.
Puede comprobarse con:
ls -l /var/run/docker.sock
getent group dockerLenguaje del código: JavaScript (javascript)
El riesgo no termina en los usuarios interactivos. También hay que comprobar qué contenedores tienen montado el socket.
Una aplicación comprometida que pueda controlar el daemon puede utilizar sus privilegios para crear contenedores con acceso a recursos del host.
Por eso pertenecer al grupo docker no debería interpretarse como un permiso operativo menor. En muchos despliegues proporciona una vía para conseguir un nivel de control equivalente al de root.
9. ACL: el permiso que puede esconderse detrás del signo +
Aquí aparece uno de los controles que una auditoría basada exclusivamente en ls -l puede pasar por alto.
Linux admite listas de control de acceso (ACL) que permiten conceder permisos adicionales a usuarios y grupos concretos.
Un archivo puede mostrar:
-rw-r-----+ 1 root root 2048 Sep 4 10:20 secrets.confLenguaje del código: CSS (css)
Ese + merece atención.
La ACL real puede consultarse mediante:
getfacl /path/to/secrets.conf
Por ejemplo, podría aparecer:
user::rw-
user:developer:r--
group::---
mask::r--
other::---Lenguaje del código: CSS (css)
Aunque los bits tradicionales parezcan restrictivos, developer tiene acceso de lectura.
Para localizar ACL extendidas puede utilizarse, según las herramientas disponibles en el sistema:
getfacl -R -s /etc /opt /srv 2>/dev/nullLenguaje del código: JavaScript (javascript)
Las ACL son útiles para administrar accesos complejos. El problema aparece cuando sobreviven a cambios de equipos, migraciones y proyectos y nadie recuerda que existen.
También deben revisarse las ACL por defecto de directorios, porque pueden propagarse automáticamente a nuevos archivos.
10. Propietarios y permisos de toda la ruta hasta el ejecutable
El décimo riesgo es menos evidente y especialmente útil en una revisión de seguridad.
Un script puede tener:
-rwxr-xr-x root root /opt/company/bin/backup.sh
A primera vista parece correcto.
Pero hay que revisar la ruta completa:
namei -l /opt/company/bin/backup.sh
Si /opt/company/bin o alguno de sus directorios padre puede ser modificado por un usuario sin privilegios, la seguridad del archivo final deja de ser suficiente.
Este tipo de revisión resulta especialmente importante en:
- scripts ejecutados mediante cron;
ExecStartde systemd;- binarios internos;
- herramientas utilizadas desde
sudo; - rutas incluidas en
$PATHde cuentas privilegiadas.
También merece la pena comprobar el $PATH utilizado por root:
sudo sh -c 'printf "%s\n" "$PATH"'Lenguaje del código: JavaScript (javascript)
Un directorio modificable por usuarios no privilegiados dentro de una ruta de búsqueda utilizada por root puede introducir oportunidades de secuestro de comandos si algún script o proceso invoca ejecutables sin una ruta absoluta.
De una lista de permisos a una política de detección
Para un administrador de sistemas, revisar estas diez categorías una vez tiene utilidad limitada. El verdadero valor aparece cuando la auditoría se convierte en detección de cambios.
SUID/SGID, capabilities, miembros de grupos privilegiados, ACL sensibles y determinados propietarios pueden almacenarse como referencia.
Después de una actualización importante o una instalación debería poder responderse a preguntas como:
¿Qué nuevos SUID han aparecido?
¿Qué capabilities han cambiado?
¿Quién ha entrado en el grupo docker?
¿Qué archivo de /etc ahora tiene otro propietario?
¿Qué servicio nuevo se ejecuta como root?
También conviene recordar que -xdev limita find al sistema de archivos inicial. Es útil para evitar recorrer NFS, volúmenes montados, pseudo-filesystems o enormes conjuntos de datos, pero también significa que esos sistemas de archivos no están siendo auditados. Si /home, /var, /opt o los datos de aplicaciones están en particiones independientes, habrá que revisarlos expresamente.
SELinux y AppArmor tampoco sustituyen estos controles. Pueden limitar lo que un proceso comprometido consigue hacer, pero los permisos Unix, ACL, capabilities y propietarios continúan formando parte de la decisión de acceso.
Una auditoría de seguridad Linux debería buscar, sobre todo, relaciones inesperadas: un usuario que puede escribir donde no debería y un proceso con más privilegios que posteriormente confía en ese recurso.
Ahí es donde un aparentemente aburrido chmod, una ACL olvidada o la pertenencia a un grupo pueden dejar de ser un problema administrativo y convertirse en una vía de escalada.
Preguntas frecuentes
¿Qué permisos debería revisar primero un administrador Linux?
SUID/SGID, archivos escribibles por todos, sudoers, tareas ejecutadas como root, Linux capabilities y grupos con privilegios indirectos ofrecen un buen punto de partida. Después conviene ampliar la auditoría a ACL, propietarios y rutas de ejecución.
¿Por qué ls -l no muestra todos los permisos efectivos?
Porque Linux puede utilizar ACL extendidas además de los bits tradicionales de propietario, grupo y otros. getfacl permite comprobar los permisos adicionales asociados a usuarios y grupos concretos.
¿Pertenecer al grupo docker equivale a ser root?
En una instalación Docker convencional debe tratarse como un privilegio equivalente o muy próximo a root. El acceso al daemon permite realizar operaciones que pueden proporcionar acceso al sistema anfitrión.
¿Cada cuánto deberían auditarse los permisos de un servidor Linux?
Depende del entorno, pero resulta especialmente útil revisar cambios después de actualizaciones, instalaciones, despliegues y modificaciones administrativas. Los sistemas críticos pueden automatizar además comparaciones periódicas contra un baseline conocido.







