1. Fundamentos del control de acceso y modelos de identidad

El control de acceso constituye uno de los pilares fundamentales de la seguridad del sistema operativo Linux. En un entorno multiusuario, cada acción, proceso o recurso está asociado a una identidad digital representada por un usuario. Estos usuarios pueden ser personas, servicios o procesos del sistema.

Linux gestiona el acceso a recursos bajo el principio DAC (Discretionary Access Control) o Control de Acceso Discrecional, en el cual el propietario de un objeto (archivo, directorio, dispositivo, etc.) decide qué permisos se otorgan a otros usuarios o grupos. Este modelo es flexible, pero puede ser peligroso si no se combina con políticas estrictas de seguridad.

Principio de mínimo privilegio

Todo usuario o proceso debe tener únicamente los permisos necesarios para realizar su función, y nada más. Este principio limita el impacto de un error o compromiso de cuenta.

1.1. Tipos de usuarios en Linux

En Linux, los usuarios se clasifican en tres grandes grupos:

  1. Superusuario o root (UID 0): Tiene acceso total al sistema. Puede leer, modificar o eliminar cualquier archivo, y ejecutar cualquier comando sin restricciones.

    • El UID 0 identifica al superusuario.

    • Cualquier cuenta de usuario que tenga el UID 0 tiene los mismos privilegios que root, aunque se llame distinto. Por ejemplo, admin con UID 0.

    • Es un comportamiento programado a nivel de kernel. Por defecto, un proceso con UID 0 recibe todas las capabilities y no está sujeto a las comprobaciones de permisos DAC. Este poder solo puede restringirse con mecanismos adicionales como la reducción de capabilities, los módulos de control de acceso obligatorio (SELinux, AppArmor) o los espacios de nombres de usuario.

    • Es recomendable evitar el acceso directo en el sistema como root y usar sudo para tareas administrativas puntuales.

  2. Usuarios del sistema (UID 1-999): Estos usuarios son creados automáticamente por el sistema o por servicios instalados como mysql, www-data o daemon.

    • No tienen acceso interactivo, por lo tanto, su shell suele ser /usr/sbin/nologin.

    • Se usan para aislar procesos y evitar que un servicio comprometido afecte a todo el sistema.

    • En Debian, los UID 1-99 se asignan de forma estática (paquete base-passwd) y los UID 100-999 se asignan dinámicamente a los servicios que se instalan. Este rango se define con los parámetros SYS_UID_MIN y SYS_UID_MAX de /etc/login.defs.

    • Existe una excepción conocida, el usuario nobody (UID 65534), que es una cuenta sin privilegios usada por algunos servicios aunque su UID sea mayor que 1000.

    • Aunque la convención actual es reservar los UID entre 0 y 999 para el sistema, cada distribución puede utilizar un rango diferente. A continuación se muestra una tabla de los valores utilizados en algunas distribuciones.

Distribución / Familia Rango de UID reservados para el sistema Descripción

Debian / Ubuntu

0 - 999

A partir de UID 1000 son usuarios normales.

Red Hat / CentOS / Fedora

0 - 999

Desde RHEL 7. En versiones antiguas (RHEL ≤ 6) el rango era 0 - 499 y los usuarios normales empezaban en el UID 500.

Arch Linux / Manjaro

0 - 999

Siguen la convención moderna.

SUSE / openSUSE

0 - 999

Igual que Debian.

  1. Usuarios normales (UID ≥ 1000): Son las cuentas de personas que interactúan con el sistema.

    • Disponen de un directorio personal (/home/usuario).

    • Solo disponen de los permisos que les concede el DAC: control sobre sus propios recursos y acceso a los archivos que otros hayan hecho legibles, como /etc/passwd.

    • Pueden hacer uso de un shell interactivo como /bin/bash o /bin/zsh.

    • Tienen un grupo principal con el mismo nombre que el usuario y, normalmente, un GID igual al UID (siempre que ese GID esté libre).

    • No tienen privilegios administrativos a menos que se les otorgue mediante sudo.

Los valores de UID_MIN y UID_MAX se configuran en el archivo /etc/login.defs. Puede consultar cuáles son los valores actuales del sistema con el siguiente comando:

grep -E '^UID_(MIN|MAX)' /etc/login.defs
Elemento Significado

grep

Muestra las líneas de un archivo que cumplen un patrón

-E

Activa las expresiones regulares extendidas

^UID_

^ ancla el patrón al inicio de la línea, de modo que se ignoran los comentarios que mencionan UID_MIN

(MIN|MAX)

El operador | actúa como OR lógico y busca cualquiera de los dos patrones, y los paréntesis lo agrupan

En Ubuntu 24.04 LTS, la salida del comando anterior devolvería los siguientes valores:

UID_MIN 1000
UID_MAX 60000

1.2. El modelo User Private Groups (UPG)

En los sistemas UNIX tradicionales, existía un modelo en el que todos los usuarios comunes pertenecían por defecto al mismo grupo principal compartido, comúnmente llamado users, con GID 100. Este esquema planteaba problemas de privacidad, ya que si un usuario otorgaba permisos de lectura o escritura a su grupo en un archivo, cualquier otro usuario del sistema podía acceder a él o modificarlo.

Para solventar esta debilidad, las distribuciones Linux modernas implementan de forma predeterminada el esquema UPG (User Private Group), que consiste en:

  1. Grupo exclusivo por usuario: Cada vez que se crea un nuevo usuario, el sistema crea automáticamente un grupo privado con su mismo nombre y, si está disponible, un GID idéntico a su UID.

  2. Aislamiento por defecto: El usuario es el único miembro de su grupo principal, garantizando que sus archivos personales nunca queden expuestos inadvertidamente a otros usuarios a través del grupo.

  3. Flexibilidad para el trabajo en equipo: Si varios usuarios necesitan colaborar en un proyecto compartido, el administrador no necesita alterar sus grupos principales, basta con crear un grupo secundario específico y asignarles acceso a un directorio de trabajo común.

En el capítulo Permisos y control de acceso básico se estudiará en detalle cómo se configuran los permisos de grupo, la máscara umask y el permiso especial SetGID para habilitar el trabajo colaborativo en carpetas compartidas.

Este comportamiento está regulado en /etc/login.defs mediante la directiva:

USERGROUPS_ENAB yes

Si esta opción está establecida en yes, useradd crea el grupo privado de cada cuenta nueva y, cuando se elimina un usuario con el comando userdel, el sistema también elimina automáticamente su grupo privado si este no tiene más miembros.

2. Archivos esenciales de cuentas y seguridad de credenciales

Linux utiliza varios archivos de texto plano ubicados en el directorio /etc que constituyen la base de la autenticación local:

Archivo Función principal Permisos recomendados

/etc/passwd

Contiene información básica sobre las cuentas (nombre, UID, GID principal, directorio personal y shell).

644 (root:root)

/etc/shadow

Almacena los hashes de las contraseñas y las directivas temporales de caducidad.

640 (root:shadow)

/etc/group

Define los grupos del sistema y sus listas de miembros secundarios.

644 (root:root)

/etc/gshadow

Almacena las contraseñas de grupo y los administradores delegados de cada grupo.

640 (root:shadow)


2.1. Archivo /etc/passwd

Es un archivo de texto plano accesible por todos los usuarios del sistema (permisos 644), ya que muchas herramientas y utilidades necesitan traducir UIDs numéricos a nombres de usuario legibles.

2.1.1. Estructura

Cada línea representa una cuenta de usuario y está dividida en siete campos separados por dos puntos (:):

usuario:contraseña:UID:GID:descripción:directorio_personal:shell

2.1.2. Campos principales

Campo Descripción Ejemplo Explicación técnica

usuario

Nombre de la cuenta

maria

Identificador de inicio de sesión (login). En sistemas modernos sigue las convenciones POSIX (minúsculas, dígitos, guion y guion bajo).

contraseña

Puntero de autenticación

x

En sistemas con contraseñas ocultas (shadow passwords), este campo siempre contiene una x. Indica que el hash real de la contraseña reside en /etc/shadow.

UID

Identificador numérico de usuario

1001

Número único asignado al usuario. El valor 0 está reservado a root.

GID

Identificador del grupo principal

1001

GID numérico del grupo principal del usuario, definido en /etc/group. Con UPG suele coincidir con el UID.

descripción

Campo de información GECOS

Maria Garcia

Campo de texto libre para el nombre real, departamento, teléfono o ubicación. Puede modificarse con chfn.

directorio_personal

Ruta del directorio personal

/home/maria

Directorio de inicio del usuario tras autenticarse con éxito. Las cuentas de servicio suelen apuntar a /var/lib/…​ o /nonexistent.

shell

Intérprete de comandos

/bin/bash

Programa ejecutado al iniciar sesión interactiva. Si contiene /usr/sbin/nologin o /bin/false, el usuario no puede iniciar sesión interactiva.

2.1.3. Ejemplo

Podemos inspeccionar una entrada de /etc/passwd mediante grep:

grep '^maria:' /etc/passwd
maria:x:1001:1001:Maria Garcia:/home/maria:/bin/bash       (1) (2) (3) (4) (5) (6) (7)
1 Nombre de usuario.
2 Contraseña delegada en /etc/shadow.
3 UID del usuario.
4 GID de su grupo principal.
5 Comentario o campo GECOS.
6 Directorio personal asignado.
7 Intérprete de comandos inicial.
Elemento Significado

grep

Muestra las líneas de un archivo que cumplen un patrón

'^maria:'

Selecciona las líneas que empiezan por maria:. El signo ^ indica el inicio de la línea y los dos puntos evitan confundir a maria con cuentas como mariano

/etc/passwd

Archivo en el que se busca


2.2. Archivo /etc/shadow y seguridad de credenciales

Históricamente, los hashes de las contraseñas se almacenaban en el segundo campo de /etc/passwd. Dado que este archivo debe ser legible por cualquier proceso, cualquier usuario local podía extraer los hashes e intentar descifrarlos mediante ataques de fuerza bruta o diccionario. Para resolver este riesgo se introdujo /etc/shadow, accesible únicamente por el superusuario y por procesos autorizados.

Hash no es lo mismo que cifrado

Es habitual leer que las contraseñas se guardan “cifradas”, pero técnicamente no es correcto:

  • Cifrado: Es una transformación reversible. Con la clave adecuada se recupera el texto original.

  • Hash: Es una función criptográfica unidireccional. No existe ninguna clave que permita recuperar la contraseña original a partir del resultado.

Para verificar una contraseña en el inicio de sesión, el sistema aplica la misma función de hashing con la sal almacenada a lo que escribe el usuario y compara el resultado con el hash de /etc/shadow. Si coinciden, el acceso se concede.

La sal (salt) es una cadena aleatoria generada por el sistema que se concatena a la contraseña antes de calcular el hash. Cumple dos objetivos de seguridad vitales:

  1. Impide el uso de tablas precalculadas (rainbow tables), ya que el atacante tendría que calcular una tabla distinta para cada sal posible.

  2. Garantiza que dos usuarios con la misma contraseña tengan hashes completamente distintos en el archivo.

Lecturas recomendadas

Los siguientes artículos permiten profundizar en el concepto de sal criptográfica y en las directrices de almacenamiento seguro de contraseñas:

2.2.1. Estructura de /etc/shadow

Cada línea contiene nueve campos separados por dos puntos (:):

usuario:contraseña:lastchange:min:max:warn:inactive:expire:reserved
Campo Descripción Ejemplo Explicación técnica

usuario

Nombre de la cuenta

maria

Debe coincidir exactamente con una entrada existente en /etc/passwd.

contraseña

Hash de la contraseña

$y$j9T$WOMmh…​

Contiene el algoritmo, la sal y el hash. Si empieza por ! o vale *, la autenticación por contraseña está deshabilitada (ver apartado 3.6).

lastchange

Fecha del último cambio

20378

Número de días transcurridos desde el 1 de enero de 1970 (epoch time). Puede convertirse a fecha legible con date -d "1970-01-01 +20378 days".

min

Días mínimos entre cambios

7

Días que deben transcurrir antes de que el usuario pueda cambiar su contraseña de nuevo. Evita que un usuario burle el historial de contraseñas cambiándola muchas veces seguidas.

max

Días máximos de validez

90

Periodo máximo tras el cual la contraseña debe renovarse obligatoriamente.

warn

Días de aviso previo

14

Antelación con la que el sistema comienza a advertir al usuario de la inminente expiración al iniciar sesión.

inactive

Días de inactividad tras expiración

30

Días de gracia tras expirar la contraseña antes de desactivar la cuenta por completo.

expire

Fecha de expiración absoluta

20999

Fecha en formato de días desde 1970 en que la cuenta deja de funcionar, independientemente de la contraseña.

reserved

Campo reservado

vacío

Reservado para usos futuros.

La orden date -d "1970-01-01 +20378 days" convierte esos días en una fecha legible:

Elemento Significado

date

Muestra la fecha y la hora

-d

Indica una fecha concreta en lugar de la actual

"1970-01-01 +20378 days"

Suma 20378 días al origen de la época UNIX

2.2.2. Formato de registro y prefijos de algoritmos de hash

El campo de contraseña contiene el hash y los metadatos del algoritmo utilizado conforme a la estructura general:

$id$params$salt$hash

Donde cada segmento cumple un propósito específico:

  • $id: Identifica el algoritmo de hash empleado en la derivación.

  • $params: Parámetros de coste del algoritmo. Aparecen de forma obligatoria en yescrypt para fijar la dificultad de CPU y memoria, y de forma opcional en otros algoritmos como SHA-256 o SHA-512.

  • $salt: Cadena aleatoria única que individualiza el cálculo y evita la reutilización de ataques precalculados.

  • $hash: Cadena final resultante de aplicar la función criptográfica unidireccional.

En las funciones de hashing para contraseñas, la rapidez de cómputo constituye una debilidad. Cuanto más veloz es el cálculo de un hash, mayor es la cantidad de combinaciones por segundo que un atacante puede evaluar en ataques de fuerza bruta o diccionario. Por este motivo, los algoritmos modernos se diseñan deliberadamente para ser lentos y demandantes de recursos del sistema.

A continuación se resumen los prefijos más habituales que identifican al algoritmo en el segundo campo de /etc/shadow:

Prefijo Algoritmo Estado de seguridad

$y$

yescrypt

Recomendado por defecto en Debian 11, Debian 12 (Bookworm), Ubuntu 22.04 LTS y distribuciones recientes de Fedora. Resistente a ataques masivos con GPU (ver apartado 6.1).

$6$

SHA-512

Estándar robusto anterior. Seguro, aunque más vulnerable a aceleración por hardware que yescrypt.

$5$

SHA-256

Seguro, sustituido progresivamente por SHA-512 y yescrypt.

$2b$ / $2y$

bcrypt

Muy seguro, basado en el cifrador Blowfish. Habitual en entornos BSD y aplicaciones web.

$1$

MD5

Obsoleto e inseguro. Es muy rápido de calcular y no usa memoria, por lo que permite ataques de fuerza bruta ultrarrápidos.

Vacío (::)

Sin contraseña

Riesgo crítico. Permite el inicio de sesión local sin ninguna autenticación.

2.2.3. Herramientas de interacción segura con /etc/shadow

El archivo /etc/shadow nunca debe manipularse con editores de texto convencionales como nano o vim. Abrir el archivo directamente carece de mecanismos de bloqueo de concurrencia, lo que puede provocar condiciones de carrera y corromper la base de datos de credenciales si otro proceso modifica el archivo al mismo tiempo, por ejemplo un usuario que cambia su contraseña con passwd.

Para interactuar, auditar y modificar este archivo de forma segura, el sistema proporciona herramientas específicas:

  1. Auditoría del estado de credenciales (passwd -S):
    Permite consultar el estado de la contraseña y sus parámetros de caducidad en una línea estructurada, sin exponer el hash criptográfico en pantalla. Combinado con la opción -a, audita todas las cuentas locales del sistema en una sola operación:

    sudo passwd -S maria
    sudo passwd -Sa
    Parámetro Significado

    -S

    Muestra el estado (status) de la contraseña de una cuenta en lugar de cambiarla. Sin esta opción, passwd maria pediría una contraseña nueva

    -a

    Aplica la consulta a todas las cuentas (all). Solo se usa junto con -S

    La salida tiene una línea por cuenta con este formato:

    maria P 2026-10-19 7 90 14 30

    Los campos son, por orden: el nombre de la cuenta, el estado (P, L o NP), la fecha del último cambio de contraseña y los valores de min, max, warn e inactive de /etc/shadow (días mínimos entre cambios, días máximos de validez, días de aviso y días de inactividad).

    El estado puede tomar tres valores, según el contenido del campo de contraseña de /etc/shadow:

    • P, contraseña utilizable: El campo contiene un hash válido. La cuenta puede autenticarse con contraseña.

    • L, contraseña bloqueada: El campo empieza por !, como ocurre tras passwd -l o usermod -L, o vale *, como en la mayoría de las cuentas del sistema. Nadie puede autenticarse con contraseña, pero siguen siendo posibles otros métodos como las claves SSH.

    • NP, sin contraseña: El campo está vacío. Cualquiera puede entrar en la cuenta sin autenticarse, por lo que es un riesgo crítico que debe corregirse de inmediato, por ejemplo bloqueando la cuenta con passwd -l o asignándole una contraseña.

  2. Verificación de integridad referencial (pwck -r):
    Este comando verifica que todas las entradas de /etc/passwd y /etc/shadow tienen el formato adecuado y contienen datos válidos, y propone eliminar las que están mal formadas o tienen errores que no se pueden corregir. La opción -r lo ejecuta en solo lectura, de modo que no modifica los archivos.

    sudo pwck -r

    Las comprobaciones sobre /etc/shadow se activan porque ese archivo existe en el sistema. En total, el comando verifica:

    Archivo Comprueba que

    /etc/passwd

    Cada entrada tiene el número correcto de campos

    /etc/passwd

    El nombre de usuario es único y válido

    /etc/passwd

    El identificador de usuario y el de grupo son válidos

    /etc/passwd

    El grupo principal es válido

    /etc/passwd

    El directorio personal es válido

    /etc/passwd

    El intérprete de comandos es válido

    /etc/shadow

    Cada entrada de passwd tiene su entrada en shadow, y viceversa

    /etc/shadow

    Las contraseñas están almacenadas en shadow

    /etc/shadow

    Las entradas tienen el número correcto de campos y no se repiten

    /etc/shadow

    Las fechas del último cambio de contraseña no están en el futuro

  3. Edición segura con bloqueo exclusivo (vipw -s):
    Bloquea el acceso al archivo creando el cerrojo /etc/shadow.lock, el cual almacena el identificador de proceso (PID) para impedir modificaciones simultáneas por otros programas, y genera la copia temporal /etc/shadow.edit sobre la que opera el editor. Una vez guardado y cerrado el editor, aplica los cambios de forma atómica sobre el archivo definitivo y preserva los permisos 640 y el grupo propietario shadow. vipw no valida el contenido: acepta líneas con un formato incorrecto y solo recuerda que puede ser necesario revisar el archivo relacionado, por lo que tras editarlo conviene ejecutar sudo pwck -r o sudo grpck -r. Para editar /etc/gshadow se emplea de forma análoga sudo vigr -s, generando /etc/gshadow.lock y /etc/gshadow.edit.

    sudo vipw -s
    Orden Archivo que edita

    vipw

    /etc/passwd

    vipw -s

    /etc/shadow, porque -s (shadow) cambia el archivo de destino

    vigr

    /etc/group

    vigr -s

    /etc/gshadow


2.3. Archivos de grupos: /etc/group y /etc/gshadow

Los grupos permiten organizar a los usuarios por funciones, departamentos o niveles de acceso a recursos:

grupo:contraseña:GID:miembros
  1. /etc/group (permisos 644 root:root):

    • grupo: Nombre del grupo (ej. soporte).

    • contraseña: Marcador x que indica delegación en /etc/gshadow.

    • GID: Identificador numérico del grupo.

    • miembros: Lista de usuarios secundarios separados por comas. El usuario cuyo grupo principal coincide con el GID no necesita figurar en esta lista.

  2. /etc/gshadow (permisos 640 root:shadow):

    • Contiene contraseñas de grupo y la lista de administradores de grupo que pueden gestionar miembros con gpasswd sin necesidad de privilegios de root (ver apartado 4.2).

    • Se edita de forma segura mediante sudo vigr -s.


2.4. Permisos críticos y copias de seguridad (CIS)

Las utilidades de cuentas (useradd, usermod, passwd, etc.) crean copias de seguridad automáticas con sufijo de guion (-) al efectuar cambios. El CIS Benchmark para Ubuntu Linux incluye una recomendación específica para cada una de estas copias (/etc/passwd-, /etc/group-, /etc/shadow- y /etc/gshadow-) con los mismos permisos máximos que los archivos originales:

sudo chmod 644 /etc/passwd /etc/passwd- /etc/group /etc/group-
sudo chown root:root /etc/passwd /etc/passwd- /etc/group /etc/group-
sudo chmod 640 /etc/shadow /etc/shadow- /etc/gshadow /etc/gshadow-
sudo chown root:shadow /etc/shadow /etc/shadow- /etc/gshadow /etc/gshadow-
Orden Significado

chmod 644 archivo

chmod cambia los permisos. El número tiene tres cifras, para propietario, grupo y resto, y cada una suma 4 por lectura, 2 por escritura y 1 por ejecución. 644 equivale a rw-r—​r-- y 640 a rw-r-----

chown root:shadow archivo

chown cambia el propietario y el grupo, con el formato propietario:grupo. Aquí el propietario es root y el grupo es shadow

Ambas órdenes admiten varios archivos a la vez, por lo que cada línea trata el archivo original y su copia con sufijo -. Los permisos se estudian en el capítulo de permisos y control de acceso básico.

Con los conceptos explicados en este capítulo sobre los archivos de cuentas, formatos de hash, sal y algoritmos, ya puede realizar:

3. Ciclo de vida y bastionado de cuentas de usuario

La administración segura de identidades abarca el ciclo de vida completo de cada cuenta: creación controlada, asignación de plantillas, auditoría de permisos, mantenimiento de atributos, políticas de caducidad y baja segura sin dejar rastros residuales.


3.1. Creación de usuarios: bajo y alto nivel

En sistemas GNU/Linux coexisten dos herramientas principales para dar de alta cuentas:

  • useradd (bajo nivel): Binario estándar disponible en todas las distribuciones Linux. Es ideal para scripts y automatizaciones porque opera exactamente según los parámetros especificados, sin formular preguntas interactivas. En Debian y Ubuntu no crea el directorio personal salvo que se indique explícitamente con la opción -m.

  • adduser (alto nivel): Script interactivo presente en Debian, Ubuntu y derivadas. Guía al administrador paso a paso, solicita la contraseña, crea el directorio personal con permisos seguros y aplica la plantilla /etc/skel de forma automática. En Red Hat y Fedora, adduser es simplemente un enlace simbólico a useradd.

3.1.1. Opciones principales de useradd

Parámetro Función Ejemplo de uso

-m

Crea el directorio personal si no existe.

sudo useradd -m juan

-s

Define el intérprete de comandos (shell).

sudo useradd -s /bin/bash juan

-c

Añade información en el campo GECOS o comentario.

sudo useradd -c "Auditor Externo" juan

-d

Especifica una ruta personalizada para el directorio personal.

sudo useradd -d /var/www/app juan

-e

Fija una fecha de expiración absoluta (AAAA-MM-DD).

sudo useradd -e 2027-06-30 juan

-f

Días de gracia tras caducar la clave antes de desactivar la cuenta.

sudo useradd -f 30 juan

-r

Crea una cuenta del sistema (UID en rango SYS_UID_MIN-SYS_UID_MAX).

sudo useradd -r appsvc

-M

Fuerza a no crear el directorio personal (útil en servicios).

sudo useradd -r -M appsvc

3.1.2. Opciones principales de adduser

adduser acepta opciones con nombre largo, más legibles que las abreviaturas de useradd, y lee sus valores por defecto de /etc/adduser.conf. Por eso no necesita -m: crea el directorio personal por sí solo. Sin opciones, sudo adduser juan crea la cuenta con su grupo privado y su directorio personal, y pide la contraseña y los datos del campo GECOS.

Parámetro Función Equivalente en useradd

--disabled-password

No pide la contraseña y deja la cuenta sin ella: no se puede entrar con contraseña, pero sí con otros métodos como las claves SSH

(sin equivalente directo)

--disabled-login

No ejecuta passwd, por lo que la persona no podrá usar la cuenta hasta que se le asigne una contraseña

(sin equivalente directo)

--system

Crea una cuenta del sistema, sin contraseña y con /usr/sbin/nologin como shell

-r

--ingroup

Usa un grupo existente como grupo principal en lugar de crear uno privado

-g

--comment, --shell, --home, --uid

Rellenan el campo GECOS, el intérprete, el directorio personal y el UID

-c, -s, -d, -u

Además de crear cuentas, adduser añade un usuario existente a un grupo existente con la forma adduser usuario grupo:

sudo adduser juan soporte

3.1.3. Creación segura de cuentas de servicio

Las cuentas que ejecutan servicios del sistema (como bases de datos o servidores web) nunca deben tener acceso interactivo ni directorios innecesarios:

sudo useradd -r -M -d /var/lib/appsvc -s /usr/sbin/nologin -c "Servicio de aplicacion" appsvc
Parámetro Efecto

-r

Asigna un UID del rango de sistema

-M

No crea el directorio personal, ni siquiera en /home

-d /var/lib/appsvc

Anota esa ruta como directorio personal en /etc/passwd

-s /usr/sbin/nologin

Impide el inicio de sesión interactivo y muestra el mensaje «This account is currently not available»

-c

Rellena el campo GECOS con una descripción de la cuenta

Como useradd no muestra ninguna salida cuando termina bien, el resultado se verifica con dos órdenes:

getent passwd appsvc
sudo passwd -S appsvc

getent passwd muestra la entrada de la cuenta a través de NSS (Name Service Switch), la capa de consulta de identidades que se estudia en el apartado 6.3. Permite comprobar que el UID queda por debajo de UID_MIN, que el directorio personal es el indicado con -d y que el intérprete es /usr/sbin/nologin.

passwd -S muestra el estado de la contraseña sin exponer el hash, y requiere sudo porque lee /etc/shadow. El estado esperado es L, que indica que no existe una contraseña con la que autenticarse. Si apareciera NP, la cuenta no tendría contraseña y sería una puerta de acceso abierta.

Por último, conviene comprobar las dos caras de una cuenta de servicio, que no admite una sesión interactiva pero sí ejecuta procesos:

# Intenta abrir una sesión de login. Con sudo no se pide contraseña,
# pero el intérprete nologin rechaza la sesión
sudo su - appsvc

# Ejecuta una orden con la identidad de la cuenta, sin abrir ninguna shell
sudo -u appsvc id

La primera orden termina con el mensaje «This account is currently not available», porque su - necesita el intérprete que figura en /etc/passwd y ese intérprete, /usr/sbin/nologin, se limita a mostrar ese aviso y salir. La segunda, en cambio, muestra el UID, el GID y los grupos de appsvc, ya que sudo -u ejecuta el programa directamente con esa identidad sin pasar por la shell de inicio de sesión.

Esta es la misma situación de un servicio gestionado por systemd con la directiva User=appsvc, que arranca el ejecutable con esa identidad sin consultar en ningún momento el campo de intérprete de la cuenta. Por eso nologin cierra la vía interactiva sin impedir que la cuenta cumpla su función.


3.2. Valores predeterminados y plantillas globales

Cuando useradd se invoca sin parámetros específicos, aplica la configuración por defecto definida en /etc/default/useradd y en /etc/login.defs.

Si ejecutamos el siguiente comando se mostrarán cuáles son los valores que se aplicarán por defecto:

sudo useradd -D

Una posible salida de ejemplo es la siguiente:

GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/sh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no
LOG_INIT=yes

Cada línea es una variable de /etc/default/useradd:

Variable Significado Valor del ejemplo

GROUP

GID del grupo principal por defecto. Solo se usa cuando las cuentas no reciben un grupo privado. Con USERGROUPS_ENAB yes en /etc/login.defs, que es lo habitual en Debian, Ubuntu y Red Hat, cada cuenta nueva recibe su propio grupo, según el modelo UPG, y este valor se ignora

100, el grupo users

HOME

Directorio base en el que se crean los directorios personales, de modo que el de juan sería /home/juan

/home

INACTIVE

Días de gracia tras caducar la contraseña antes de desactivar la cuenta. El valor -1 desactiva esta función

-1

EXPIRE

Fecha de expiración que reciben las cuentas nuevas. Si está vacía, no caducan

vacío

SHELL

Intérprete de comandos por defecto cuando no se indica -s. useradd es una herramienta de bajo nivel y usa /bin/sh por ser el más general

/bin/sh

SKEL

Directorio plantilla cuyos archivos se copian al directorio personal de la cuenta nueva, como se explica en el apartado 3.2.1

/etc/skel

CREATE_MAIL_SPOOL

Indica si se crea el buzón de correo de la cuenta

no

LOG_INIT

Indica si la cuenta se registra en las bases de datos de último acceso y de intentos fallidos, lastlog y faillog

yes

El archivo /etc/default/useradd solo es legible por root. Sin sudo, useradd -D no puede leerlo y muestra los valores de compilación en lugar de los configurados, por lo que una consulta sin privilegios puede dar una imagen falsa de la política vigente.

Orden Efecto

sudo useradd -D

-D (defaults) hace que useradd no cree ninguna cuenta y muestre los valores por defecto

sudo useradd -D -f 30

Modifica de forma persistente el valor de INACTIVE. El parámetro -f fija en 30 los días de inactividad máxima tras expirar la contraseña

sudo useradd -D -f -1

Restaura el valor original, que desactiva la inactividad

Las variables de /etc/login.defs, como PASS_MAX_DAYS, HOME_MODE o UMASK, no son retroactivas: solo se aplican a las cuentas que se creen después de modificarlas. Sus valores se detallan en el ejercicio 4.

3.2.1. El directorio plantilla /etc/skel

Cuando se crea un nuevo usuario con la opción -m, el sistema copia en su directorio personal todos los archivos y carpetas contenidos en /etc/skel, asignándoles como propietario al nuevo usuario. Permite estandarizar configuraciones de inicio (.bashrc, .profile) y definir máscaras de creación restrictivas (umask 027).

Los archivos de inicio de la shell

En Ubuntu 24.04, /etc/skel contiene tres archivos ocultos, cuyo nombre empieza por punto. Son scripts que la shell Bash ejecuta automáticamente en momentos distintos:

Archivo Cuándo se ejecuta Contenido habitual

.profile

Al iniciar una sesión de login, como una consola, una conexión SSH o su -. Bash lo lee si no existen .bash_profile ni .bash_login

Variables de entorno como PATH, la orden umask y la carga de .bashrc. En Ubuntu, .profile ejecuta .bashrc para que ambos se apliquen en una sesión de login

.bashrc

Cada vez que se abre una shell interactiva que no es de login, como una terminal gráfica

Alias, aspecto del prompt, historial y autocompletado

.bash_logout

Al cerrar una sesión de login

Tareas de limpieza, como borrar la pantalla

Como los usuarios pueden editar estos archivos, una configuración de seguridad que dependa solo de ellos puede ser eliminada, como se explica más abajo.

La máscara umask

La máscara de creación de archivos o umask indica qué permisos se quitan a los archivos y directorios nuevos. Los permisos de partida son 666 en los archivos, porque no se crean ejecutables, y 777 en los directorios. A cada uno se le retiran los bits que la máscara tiene activos, de modo que la máscara 027 quita la escritura al grupo y todos los permisos a otros.

umask Archivos nuevos Directorios nuevos Efecto

022

644

755

Todo el sistema puede leer y recorrer lo que crea el usuario

002

664

775

El grupo también puede escribir. Es el valor efectivo en Ubuntu para cuentas con grupo privado

027

640

750

El grupo puede leer, y el resto de usuarios queda sin acceso. Es la máscara que recomienda el CIS Benchmark

077

600

700

Solo el propietario accede

La orden umask, sin argumentos, muestra la máscara de la shell actual, y umask 027 la cambia solo para esa sesión. Para que se aplique siempre, debe fijarse en un script de inicio, como el .profile de /etc/skel, o de forma global con la directiva UMASK de /etc/login.defs, que el módulo pam_umask aplica en cada inicio de sesión. En Ubuntu 24.04, UMASK vale 022, pero con USERGROUPS_ENAB yes y un grupo privado la máscara efectiva es 002. El capítulo de permisos y control de acceso básico estudia los permisos con más detalle.

/etc/skel no impone políticas globales ni es retroactivo

  1. Sus archivos solo se copian al crear la cuenta: modificar /etc/skel no afecta a las cuentas ya existentes.

  2. Los archivos copiados pertenecen al usuario, quien puede modificarlos o eliminarlos libremente desde su terminal.

Para imponer directivas obligatorias e inmutables que los usuarios no puedan eludir, deben emplearse mecanismos globales del sistema: la directiva UMASK de /etc/login.defs o scripts de solo lectura en /etc/profile.d/ (ver apartado 7.2).


3.3. Permisos del directorio personal /home y directivas CIS

Uno de los fallos de configuración más frecuentes en auditorías de seguridad radica en los permisos asignados a los directorios de los usuarios en /home.

3.3.1. El riesgo del modo permisivo 755

Históricamente, muchas distribuciones creaban los directorios personales con modo 755 (drwxr-xr-x). Con esta configuración, cualquier usuario local no privilegiado puede ingresar al directorio de otro usuario y leer sus archivos personales, proyectos y documentos confidenciales si estos conservan permisos de lectura global.

3.3.2. Configuración segura según CIS Benchmark (750 o 700)

Las directrices del CIS Benchmark exigen que los directorios personales no otorguen permisos de acceso a “otros”:

  • Modo 750 (drwxr-x---): Solo el propietario y los miembros de su grupo pueden acceder. El resto de usuarios del sistema tiene el acceso totalmente denegado.

  • Modo 700 (drwx------): Acceso exclusivo para el propietario.

Bajo el modelo UPG (ver apartado 1.2), el grupo principal de cada usuario solo lo contiene a él mismo, por lo que en la práctica 750 y 700 proporcionan idéntico nivel de aislamiento entre usuarios normales.

Para garantizar que todos los nuevos usuarios se creen con permisos restrictivos, se deben configurar las siguientes directivas:

  1. En /etc/login.defs (para useradd):

    HOME_MODE 0750
  2. En /etc/adduser.conf (para adduser en Debian y Ubuntu):

    DIR_MODE=0750

3.3.3. Auditoría y remediación de directorios existentes

Para auditar y corregir directorios personales preexistentes que presenten permisos demasiado permisivos:

# Auditar directorios accesibles por el grupo o por otros
sudo find /home -maxdepth 1 -mindepth 1 -type d -perm /027 -ls

# Corregir solo los directorios detectados, quitando la escritura de grupo y todo el acceso de otros
sudo find /home -maxdepth 1 -mindepth 1 -type d -perm /027 -exec chmod g-w,o-rwx {} +

El comando de auditoría se descompone de la siguiente manera:

Elemento Función

sudo

Permite recorrer directorios personales que el usuario actual no puede leer

find /home

Inicia la búsqueda en /home, que contiene los directorios personales

-maxdepth 1

No desciende más de un nivel por debajo de /home, de modo que no revisa el contenido de cada directorio personal

-mindepth 1

Descarta el propio /home y evalúa solo sus entradas

-type d

Selecciona únicamente directorios y descarta los archivos sueltos que pudiera haber en /home

-perm /027

Selecciona los directorios en los que al menos uno de los bits indicados esté activo

-ls

Muestra cada resultado con el formato de ls -dils: inodo, permisos, propietario, grupo, tamaño y fecha

La máscara 027 se interpreta por clases. Con el prefijo /, find selecciona los permisos que superan el valor 750 recomendado:

Clase Dígito Bits que se comprueban Se detecta cuando

Propietario

0

Ninguno

Nunca: el propietario puede tener cualquier permiso

Grupo

2

Escritura

El grupo puede escribir en el directorio

Otros

7

Lectura, escritura y ejecución

Otros usuarios tienen cualquier permiso

Por ejemplo, 700, 740 y 750 no aparecen en la lista, mientras que 751, 755 y 770 sí. El prefijo / no debe confundirse con - delante de la máscara, ya que -perm -027 exige que todos los bits estén activos y -perm 027 exige una coincidencia exacta.

La orden de corrección repite el mismo filtro y sustituye -ls por una acción:

Elemento Función

-exec chmod …​ {} +

Ejecuta chmod sobre los directorios encontrados

{}

Representa la lista de resultados

+

Los agrupa en una sola invocación en lugar de lanzar un chmod por cada uno

g-w,o-rwx

Quita la escritura al grupo y todos los permisos a otros

Se utiliza el modo simbólico g-w,o-rwx en lugar de fijar 750 porque solo retira permisos. Un chmod 750 aplicado a todos los directorios habría ampliado el acceso del grupo en los que ya estaban en 700, y habría alcanzado también a directorios que no son personales, como lost+found.


3.4. Modificación de cuentas y control de intérpretes

El comando usermod permite actualizar cualquier atributo de una cuenta existente sin necesidad de recrearla:

  • Modificar directorio personal y mover contenido:

    sudo usermod -d /home/nuevo -m usuario
  • Cambiar el nombre de usuario (login):

    sudo usermod -l nuevo_nombre antiguo_nombre
  • Añadir a grupos secundarios:

    sudo usermod -aG docker,soporte usuario
Parámetro Significado

-d ruta

Establece un nuevo directorio personal (directory). Por sí solo solo cambia la ruta anotada en /etc/passwd

-m

Mueve (move) el contenido del directorio personal antiguo al nuevo. Solo tiene efecto junto con -d

-l nuevo antiguo

Cambia el nombre de inicio de sesión (login). No renombra ni el grupo principal ni el directorio personal

-G lista

Define los grupos secundarios del usuario, separados por comas y sin espacios

-a

Añade (append) los grupos de -G a los que ya tiene, en lugar de sustituirlos. Solo se usa junto con -G

-g grupo

Cambia el grupo principal del usuario

-s shell

Cambia el intérprete de comandos de la cuenta

Las opciones -l y -d no se pueden aplicar mientras la cuenta tenga procesos en ejecución: usermod se niega y muestra el PID que lo impide. Cierre antes las sesiones del usuario o realice el cambio desde otra cuenta administrativa, nunca desde la propia sesión que se va a renombrar. Tras renombrar una cuenta, revise también las referencias al nombre antiguo en /etc/sudoers.d/, en las directivas AllowUsers de SSH y en las tareas programadas.

Atención al modificar grupos con usermod

Es imprescindible incluir la opción -a (append) junto con -G. Si se ejecuta usermod -G grupo usuario omitiendo -a, el usuario será eliminado de todos los grupos secundarios a los que perteneciera previamente y que no figuren en la nueva lista.

3.4.1. Cambio de intérprete y seguridad de /etc/shells

El comando chsh (change shell) permite a los usuarios modificar su propia shell. Sin embargo, los usuarios sin privilegios solo pueden elegir intérpretes que figuren explícitamente en el archivo /etc/shells.

Riesgo de seguridad en /etc/shells

Bajo ninguna circunstancia deben añadirse /usr/sbin/nologin ni /bin/false a /etc/shells. Servicios como servidores FTP (vsftpd) o módulos PAM consultan /etc/shells para autorizar el acceso. Si se incluye nologin en la lista de shells válidas, una cuenta bloqueada para acceso interactivo pero con contraseña válida podría autenticarse indebidamente en dichos servicios de red.

Algunas distribuciones basadas en Red Hat incluyen nologin en /etc/shells de serie, por lo que conviene comprobarlo en lugar de darlo por supuesto:

grep -E 'nologin|false' /etc/shells

La orden no debe devolver ninguna línea.


3.5. Políticas de caducidad y expiración con chage

La herramienta chage (change age) gestiona la vigencia de las contraseñas y la expiración automática de las cuentas:

Parámetro Propósito Ejemplo práctico Descripción

-l

Listar estado

sudo chage -l maria

Muestra la configuración completa de caducidad y expiración.

-M

Días máximos de validez

sudo chage -M 90 maria

Establece el periodo máximo tras el cual la contraseña debe cambiarse.

-m

Días mínimos entre cambios

sudo chage -m 1 maria

Impide cambios consecutivos en menos de 24 horas para eludir historiales de claves.

-W

Aviso previo

sudo chage -W 7 maria

Días previos a la expiración en que el usuario recibe alertas al iniciar sesión.

-I

Inactividad postcaducidad

sudo chage -I 30 maria

Días de gracia tras expirar la contraseña antes de desactivar la cuenta por completo.

-E

Fecha de expiración de cuenta

sudo chage -E 2027-06-30 maria

Fija la fecha en que la cuenta queda bloqueada de forma absoluta. Con -E -1 se elimina la expiración.

-d 0

Forzar cambio inmediato

sudo chage -d 0 maria

Marca la fecha de último cambio a 0, forzando a cambiar la clave en el próximo inicio de sesión.

Los valores de PASS_MAX_DAYS, PASS_MIN_DAYS y PASS_WARN_AGE de /etc/login.defs se copian a /etc/shadow al crear la cuenta. Modificarlos no cambia las cuentas existentes, que deben ajustarse una a una con chage. Para auditar qué cuentas con contraseña no caducan nunca o superan los 365 días de vigencia:

sudo awk -F: '$2 !~ /^[!*]/ && ($5 == "" || $5 > 365) {print $1 " -> " $5}' /etc/shadow
Elemento Significado

-F:

Usa los dos puntos como separador de campos

$2 !~ /^[!*]/

Descarta las cuentas sin contraseña utilizable, cuyo segundo campo empieza por ! o *

$5 == "" || $5 > 365

Selecciona las cuentas cuyo quinto campo, los días máximos de validez, está vacío o supera 365

print $1 " -> " $5

Muestra el nombre de la cuenta y su valor de max

Un valor vacío o 99999 indica que la contraseña no caduca.

Políticas corporativas: CIS frente a NIST SP 800-63B

El CIS Benchmark exige tradicionalmente rotación periódica forzada de contraseñas, por ejemplo, cada 90 o 365 días. Sin embargo, la guía NIST SP 800-63B desaconseja la rotación periódica arbitraria, ya que induce a los usuarios a seleccionar patrones previsibles (Verano2025!, Verano2026!). NIST recomienda priorizar la longitud, con al menos 15 caracteres cuando la contraseña es el único factor de autenticación, verificar contraseñas contra listas de credenciales comprometidas y forzar el cambio únicamente ante indicios reales de compromiso.


3.6. Bloqueo integral y baja segura de usuarios

El procedimiento para deshabilitar o eliminar una cuenta debe seguir pautas estrictas para no dejar brechas de acceso ni recursos huérfanos.

3.6.1. Bloqueo parcial frente a bloqueo completo

Existen dos niveles de bloqueo que conviene diferenciar claramente:

# Bloqueo parcial (solo contraseña). -l (lock) antepone ! al hash
sudo passwd -l maria

# Bloqueo completo de cuenta (CIS Benchmark)
sudo usermod -L -e 1 maria

El bloqueo completo combina dos parámetros de usermod, cada uno con un efecto distinto sobre /etc/shadow:

Parámetro Campo de /etc/shadow que modifica Efecto

-L

Segundo campo, el hash de la contraseña

Antepone ! al hash y deshabilita la autenticación por contraseña. No afecta a otros métodos como las claves SSH cuando sshd usa PAM

-e 1

Octavo campo, la fecha de expiración de la cuenta

Fija la expiración en el día 1 contado desde el 1 de enero de 1970, es decir, el 2 de enero de 1970. Al estar en el pasado, la cuenta aparece como caducada

La fecha de expiración de -e admite un número de días desde 1970 o una fecha con formato AAAA-MM-DD, y es la que impide el acceso por cualquier método, porque la comprueba el módulo pam_unix en la fase account, con independencia de cómo se autenticara la persona. Se puede comprobar el resultado con sudo chage -l maria, que mostrará Account expires : Jan 02, 1970.

La trampa del bloqueo con passwd -l

passwd -l y usermod -L solo anteponen un carácter de exclamación (!) al hash en /etc/shadow: deshabilitan la autenticación por contraseña, pero no bloquean la cuenta. Los métodos que no usan la contraseña local, como una clave pública de SSH en ~/.ssh/authorized_keys, siguen dando acceso. Para bloquear la cuenta de verdad hay que expirarla con usermod -L -e 1, como se explica a continuación.

El papel de UsePAM

Que la clave siga funcionando depende de la directiva UsePAM de sshd, que indica si el servidor consulta a PAM. El valor por defecto de OpenSSH es no, pero Debian y Ubuntu distribuyen /etc/ssh/sshd_config con UsePAM yes. El comportamiento, probado con OpenSSH 9.6 de Ubuntu 24.04 y una clave pública válida, es el siguiente:

Estado de la cuenta UsePAM yes UsePAM no

Sin bloquear

Acceso concedido

Acceso concedido

Solo passwd -l, con ! en el hash

Acceso concedido

Acceso denegado

Solo expiración, con usermod -e 1

Acceso denegado

Acceso denegado

Bloqueo completo, usermod -L -e 1

Acceso denegado

Acceso denegado

  • Con UsePAM yes: sshd verifica por sí mismo la firma de la clave y después consulta a PAM las fases account y session. La fase account de pam_unix comprueba las fechas de caducidad de los campos 5 a 8 de /etc/shadow, pero no el ! del hash, de modo que el bloqueo parcial pasa desapercibido.

  • Con UsePAM no: sshd no usa PAM y aplica sus propias comprobaciones sobre /etc/shadow, entre ellas el ! y la expiración, por lo que el bloqueo parcial sí impide el acceso.

La solución: expirar la cuenta

Para impedir nuevos accesos por cualquier método y con independencia de UsePAM, se debe hacer expirar la cuenta con usermod -L -e 1, que establece la fecha de expiración en el 2 de enero de 1970. Con UsePAM yes, es PAM quien rechaza el acceso, incluidas las claves SSH. El cliente recibe el mensaje «Your account has expired; please contact your system administrator» antes de que se cierre la conexión, y el motivo queda registrado en el diario de autenticación. Con UsePAM no, lo rechaza sshd y el cliente solo ve «Permission denied (publickey)».

El bloqueo, parcial o completo, no cierra las sesiones que el usuario ya tuviera abiertas, porque solo impide nuevas autenticaciones. Para comprobar el estado de la cuenta y cerrar las sesiones vigentes:

sudo passwd -S maria
sudo loginctl terminate-user maria
Orden Función

passwd -S maria

Muestra el estado de la contraseña. L confirma que está bloqueada

chage -l maria

Confirma la fecha de expiración de la cuenta

loginctl terminate-user maria

Cierra todas las sesiones de la cuenta y termina sus procesos

Aplique loginctl terminate-user solo a cuentas con un UID propio, nunca a root ni a cuentas que compartan UID con otra.

Demostración

Puede comprobar esta diferencia de forma práctica en la demostración de bloqueo parcial frente a bloqueo completo de cuentas, que reproduce la trampa conectando por SSH desde el anfitrión a una instancia de OpenStack.

Comparativa de mecanismos: Bloqueo parcial frente a Bloqueo integral
Figura 1. Comparativa de mecanismos: Bloqueo parcial frente a Bloqueo integral

Para reactivar una cuenta completamente bloqueada:

sudo usermod -U -e "" maria

La reactivación revierte cada uno de los dos efectos del bloqueo completo:

Parámetro Campo de /etc/shadow que modifica Efecto

-U

Segundo campo, el hash de la contraseña

Elimina el ! que antepuso -L, de modo que la contraseña original vuelve a ser válida

-e ""

Octavo campo, la fecha de expiración de la cuenta

Deja el campo vacío, lo que equivale a una cuenta sin fecha de expiración. Es equivalente a -e -1

Tras la reactivación, sudo chage -l maria muestra Account expires : never.

Si la cuenta no tenía contraseña antes del bloqueo y su hash era solo !, usermod -U se niega a desbloquearla y avisa de que quedaría una cuenta sin contraseña. En ese caso hay que asignar primero una contraseña con passwd maria.

Auditoría de cuentas bloqueadas o deshabilitadas con awk

El siguiente comando lista las cuentas cuya autenticación por contraseña está deshabilitada, es decir, las que tienen un ! o un * al inicio del segundo campo de /etc/shadow:

sudo awk -F: '$2 ~ /^(\*|!)/ {print $1 " -> Contraseña deshabilitada"}' /etc/shadow

A continuación se detalla la función técnica de cada uno de los elementos que componen el comando anterior:

Elemento Significado y función técnica

sudo

Ejecuta el comando con privilegios administrativos, indispensables para acceder a /etc/shadow.

awk

Herramienta de procesamiento y filtrado de texto estructurado por columnas.

-F:

Establece los dos puntos (:) como delimitador de campos en la lectura de registros.

$2

Apunta al segundo campo de cada registro, correspondiente al hash o al estado de la contraseña.

~

Operador de correspondencia que evalúa si el valor coincide con el patrón de la expresión regular (expresión ~ /patrón/).

/^(\*|!)/

Expresión regular que detecta si el campo comienza por asterisco (*) o signo de exclamación (!), identificando cuentas de servicio deshabilitadas (*, !, !!) o contraseñas bloqueadas con passwd -l cuyo hash comienza por !.

{print $1 " -> Contraseña deshabilitada"}

Bloque de acción que imprime el nombre de usuario ($1) junto con el texto descriptivo si se cumple el patrón.

/etc/shadow

Archivo del sistema sobre el que se efectúa la consulta.

Esta comprobación solo examina el segundo campo. Por eso detecta que la contraseña está deshabilitada, pero no distingue entre bloqueo parcial y completo, ni detecta las cuentas bloqueadas únicamente por caducidad. Además, * y ! no siempre indican un bloqueo aplicado por el administrador. En las cuentas del sistema significan que nunca tuvieron contraseña.

Ejercicio de investigación propuesto

Se propone como ejercicio la búsqueda de la expresión correcta del comando awk que permita realizar la auditoría de cuentas con bloqueo parcial o completo, y que además detecte las cuentas bloqueadas por caducidad.

Referencias

En los siguientes enlaces puede encontrar más información sobre la utilidad awk y expresiones regulares:

3.6.2. Procedimiento de baja segura y prevención de archivos huérfanos

Antes de invocar userdel, el administrador debe ejecutar las siguientes comprobaciones preventivas. El orden es importante. La cuenta se bloquea en primer lugar para que nadie pueda abrir una sesión nueva ni un proceso pueda relanzarse mientras se limpia el resto.

  1. Bloquear la cuenta de forma completa:

    sudo usermod -L -e 1 maria
  2. Terminar procesos y sesiones activas:

    # Sesiones abiertas de maria
    who | grep maria
    
    # PID de todos sus procesos en ejecución
    pgrep -u maria
    
    # Termina todos sus procesos con la señal SIGTERM
    sudo pkill -u maria
    
    # Si siguen en ejecución tras unos segundos, los fuerza con SIGKILL
    sudo pkill -9 -u maria
    
    # Lista los trabajos programados con at, si el paquete está instalado
    sudo atq
    
    # Desactiva sus sesiones persistentes de systemd
    sudo loginctl disable-linger maria
    
    # Elimina sus tareas programadas con cron. No muestra error si no tiene
    sudo crontab -u maria -r 2>/dev/null
    Orden Significado

    who | grep maria

    who lista las sesiones abiertas. La tubería | pasa esa lista a grep, que muestra solo las líneas que contienen maria

    pgrep -u maria

    pgrep busca procesos y muestra su número (PID). -u maria limita la búsqueda a los procesos de esa cuenta

    pkill -u maria

    pkill envía una señal a los procesos que cumplen el criterio, aquí los de maria. Por defecto es SIGTERM, una petición de terminación que un proceso puede ignorar

    pkill -9 -u maria

    -9 envía SIGKILL, que el proceso no puede ignorar. Úsela si pgrep -u maria sigue devolviendo PID

    atq

    Lista los trabajos programados con at. Como root muestra los de todos los usuarios, por lo que debe buscar los de maria. Breve tutorial sobre at

    loginctl disable-linger maria

    Impide que los servicios de usuario de maria sigan ejecutándose sin que tenga una sesión abierta. Referencia de loginctl

    crontab -u maria -r

    crontab gestiona las tareas programadas. -u maria indica de qué usuario y -r (remove) las elimina

    2>/dev/null

    Descarta los mensajes de error (salida 2) enviándolos a /dev/null, un archivo especial que descarta todo lo que recibe

  3. Hacer copia de seguridad y rastrear archivos:

    # Directorio de destino accesible solo por root
    sudo install -d -m 700 /backup
    
    # Copia comprimida de su directorio personal
    sudo tar -czvf /backup/maria_backup.tar.gz /home/maria
    
    # Restringe los permisos de la copia
    sudo chmod 600 /backup/maria_backup.tar.gz
    
    # Lista sus archivos, sin entrar en otros sistemas de archivos montados
    sudo find / -xdev -user maria -ls 2>/dev/null
    Elemento Significado

    install -d -m 700

    install -d crea el directorio indicado y -m 700 le asigna esos permisos, de modo que solo root accede a las copias

    tar -czvf

    tar agrupa varios archivos en uno solo. -c crea (create) el archivo, -z lo comprime con gzip, -v muestra los archivos que procesa (verbose) y -f indica el nombre del archivo de salida, que va a continuación

    chmod 600

    La copia contiene datos personales y credenciales como las claves de ~/.ssh, por lo que solo su propietario puede leerla y modificarla. Debe destruirse cuando deje de ser necesaria

    find / -user maria

    find busca archivos. Se parte de / y -user maria selecciona los que pertenecen a esa cuenta

    -xdev

    No entra en directorios de otro sistema de archivos. Desde / omite /proc, /sys y /dev, los volúmenes montados bajo /mnt o /media y las unidades de red. Así evita cientos de entradas de /proc, una por cada proceso de la cuenta, y acorta la búsqueda de forma notable

    -ls

    Muestra cada resultado con el formato de ls -dils

    2>/dev/null

    Descarta los mensajes de error

    Como -xdev no entra en otros sistemas de archivos, la búsqueda no encuentra los archivos de maria que estén en un disco montado aparte, como una partición independiente de /home o /var. Esos archivos deben buscarse indicando su punto de montaje.

  4. Eliminar la cuenta y su directorio:

    sudo userdel -r maria
    getent passwd maria
    Orden Función

    userdel -r maria

    Elimina la cuenta, y -r (remove) elimina también su directorio personal y su buzón de correo. Se niega a actuar si la cuenta tiene procesos activos

    getent passwd maria

    Comprueba el resultado y no debe devolver ninguna línea

    Por último, retire las referencias a la cuenta en /etc/sudoers.d/, en las directivas AllowUsers de SSH y en los sistemas externos que la usaran.

Peligro de reutilización de UID y archivos huérfanos

Al eliminar una cuenta con userdel, los archivos que pertenecieran al usuario fuera de /home conservan su UID numérico, pero quedan como archivos huérfanos al no existir ya ese UID en /etc/passwd.

Si no se indica -u, el comando useradd asigna el menor UID igual o superior a UID_MIN que además sea mayor que el de cualquier otra cuenta existente. Por eso el UID de una cuenta eliminada se reutiliza sobre todo cuando era el más alto, o cuando el administrador lo asigna a mano con -u. En ambos casos, el usuario que reciba el UID del usuario eliminado se convertirá automáticamente en propietario de todos sus archivos huérfanos. Por este motivo es imperativo rastrear y reasignar o eliminar los archivos huérfanos antes de asignar ese UID a otra persona:

sudo find / -xdev \( -nouser -o -nogroup \) -ls 2>/dev/null
Elemento Significado

-xdev

No entra en otros sistemas de archivos

-nouser

Selecciona los archivos cuyo UID no corresponde a ninguna cuenta

-nogroup

Selecciona los archivos cuyo GID no corresponde a ningún grupo

-o

Significa «o»

\( …​ \)

Agrupan las dos condiciones. Se escriben con barra invertida para que la shell no los interprete

Los archivos encontrados deben reasignarse a una cuenta responsable o eliminarse, por ejemplo con sudo find / -xdev -nouser -exec chown -h root:root {} +, una vez revisada la lista.

Con los procedimientos del ciclo de vida de usuarios explicados en este capítulo, ya puede realizar:

4. Gestión de grupos y colaboración

La administración de grupos permite organizar usuarios por departamentos, proyectos o niveles de acceso sin necesidad de compartir cuentas.


4.1. Ciclo de vida de grupos: creación, modificación y borrado

4.1.1. Crear grupos: groupadd

Igual que ocurre con las cuentas de usuario, existen dos formas de crear grupos, una de bajo nivel y otra de alto nivel, según se explicó en el apartado 3.1:

  • groupadd (bajo nivel): Binario estándar disponible en todas las distribuciones Linux. Opera exactamente según los parámetros especificados y no hace preguntas, por lo que se recomienda en scripts y automatizaciones.

  • addgroup (alto nivel): Script de Debian, Ubuntu y derivadas que acompaña a adduser. Hace lo mismo que groupadd con una sintaxis de opciones largas más legible y mensajes informativos, por lo que resulta cómodo en la administración manual.

Con groupadd, la creación de un grupo se escribe así:

sudo groupadd proyectos
sudo groupadd -g 1050 desarrollo
Parámetro Función

-g

Asigna un GID numérico específico. Así, groupadd -g 1050 desarrollo crea el grupo desarrollo con GID 1050

-r

Crea un grupo del sistema, con un GID inferior a 1000

Si no se indica un GID, groupadd asigna el siguiente libre por encima de GID_MIN, definido en /etc/login.defs.

Con addgroup, en Debian y Ubuntu, las mismas operaciones se escriben así:

sudo addgroup soporte
sudo addgroup --gid 1050 desarrollo
sudo addgroup --system servicios
Orden Equivalente con groupadd Función

addgroup soporte

groupadd soporte

Crea un grupo normal con el siguiente GID libre

addgroup --gid 1050 desarrollo

groupadd -g 1050 desarrollo

--gid asigna un GID numérico concreto

addgroup --system servicios

groupadd -r servicios

--system crea un grupo del sistema, con un GID del rango de sistema

4.1.2. Modificar grupos: groupmod

Permite actualizar las propiedades de un grupo existente:

# Cambiar el nombre del grupo
sudo groupmod -n seguridad desarrollo

# Cambiar el GID
sudo groupmod -g 1100 seguridad
Parámetro Función

-n nuevo

Indica el nuevo nombre (new name), que va antes del nombre actual

-g GID

Establece un nuevo GID

En ambos casos el último argumento es el grupo que se modifica.

Atención al modificar el GID

El comando groupmod -g actualiza /etc/group, pero no altera los archivos existentes en el sistema de archivos. Los archivos que pertenecían al grupo conservan el GID antiguo y quedan huérfanos de grupo. El administrador debe actualizar manualmente la propiedad con find:

sudo find / -xdev -gid 1050 -exec chgrp seguridad {} +
Elemento Función

-xdev

No entra en otros sistemas de archivos

-gid 1050

Selecciona los archivos con el GID antiguo

-exec chgrp seguridad …​

Ejecuta chgrp (change group), que cambia el grupo propietario, sobre los resultados

{}

Representa la lista de archivos encontrados

+

Los agrupa en una sola invocación

4.1.3. Eliminar grupos: groupdel

sudo groupdel seguridad

El comando groupdel no permite eliminar el grupo principal de ningún usuario existente (groupdel: cannot remove the primary group of user '…​'). Para poder borrarlo, primero se debe reasignar el grupo principal del usuario afectado con usermod -g o dar de baja a dicho usuario.


4.2. Delegación administrativa con gpasswd

El comando gpasswd es la utilidad asociada a /etc/gshadow. Permite gestionar membresías y delegar la administración de un grupo en usuarios específicos sin otorgarles privilegios de root:

Comando Acción realizada

sudo gpasswd -a usuario grupo

Añade un usuario al grupo secundario.

sudo gpasswd -d usuario grupo

Elimina a un usuario del grupo (revocación inmediata).

sudo gpasswd -M u1,u2,u3 grupo

Define la lista completa de miembros, sustituyendo la anterior.

sudo gpasswd -A usuario grupo

Nombra a un usuario administrador del grupo en /etc/gshadow.

sudo gpasswd -r grupo

Elimina la contraseña del grupo.

Un usuario nombrado administrador de un grupo con gpasswd -A puede ejecutar gpasswd -a y gpasswd -d sobre su propio grupo sin invocar sudo. Esto permite que responsables de proyecto gestionen quién accede a sus carpetas compartidas sin comprometer la seguridad global del sistema.

Las contraseñas de grupo permitían antiguamente que un usuario se uniera temporalmente a un grupo con newgrp mediante una clave compartida. Hoy se consideran una mala práctica contraria a la trazabilidad y están en desuso.


4.3. Trabajo colaborativo y consistencia de grupos

Para consultar las membresías de un usuario se utilizan las utilidades estándar id y groups.

id juan
groups juan
Orden Salida

id juan

El UID, el GID y todos los grupos de juan, con sus números

groups juan

Solo los nombres de sus grupos

Sin argumento, ambas órdenes consultan al usuario que las ejecuta.

Los cambios de grupo no afectan a las sesiones abiertas

La lista de grupos de un proceso se calcula en el momento exacto de iniciar sesión. Si se añade o retira a un usuario de un grupo, el cambio no tendrá efecto en sus terminales activas. El usuario debe cerrar su sesión y volver a entrar (o ejecutar newgrp nombre_grupo) para que el kernel actualice los privilegios de su proceso. Del mismo modo, si se revoca la membresía de un usuario, sus sesiones abiertas conservarán los permisos hasta que se cierren.

Con las operaciones de administración de grupos y delegación con gpasswd, ya puede realizar:

5. Privilegios administrativos y delegación con sudo

El principio de mínimo privilegio exige erradicar el trabajo cotidiano mediante la cuenta directa de root. La delegación controlada con sudo (superuser do) permite conceder permisos granulares y auditar de forma fehaciente quién ejecuta qué acción en el sistema.


5.1. El riesgo del superusuario directo

Iniciar sesión directamente como root presenta graves deficiencias de seguridad:

  • Pérdida de trazabilidad e imputabilidad: Si varias personas conocen la contraseña de root, es imposible determinar quién ejecutó una acción indebida o destructiva.

  • Impacto catastrófico de errores: Cualquier error tipográfico en comandos con privilegios totales puede corromper el sistema de archivos de forma irreversible.

  • Violación de cumplimiento: Normativas como PCI-DSS, ISO 27001 y el Esquema Nacional de Seguridad (ENS) prohíben el uso compartido de cuentas con privilegios de superusuario.


5.2. Auditoría exhaustiva de grupos privilegiados

La asignación de grupos secundarios en Linux requiere un control riguroso. Determinados grupos conceden control administrativo total sobre el sistema, mientras que otros proporcionan acceso a información confidencial que puede facilitar vectores de ataque indirectos o auditorías no autorizadas.

5.2.1. Grupos con acceso administrativo total o escalada directa a root

Pertenecer a estos grupos permite tomar el control completo del sistema o ejecutar comandos con privilegios de superusuario:

Grupo Mecanismo y vector de riesgo

sudo / wheel

Concede privilegios de superusuario a través del comando sudo, siempre que esté habilitada la directiva correspondiente en /etc/sudoers (%sudo en Debian y Ubuntu, %wheel en la familia Red Hat). A diferencia de otros mecanismos, exige autenticación por defecto y registra los comandos ejecutados.

docker

En la instalación tradicional con demonio centralizado (rootful), el demonio se ejecuta como root. Pertenecer al grupo docker permite comunicarse con /var/run/docker.sock y desplegar contenedores que monten la raíz del anfitrión (por ejemplo: docker run -v /:/mnt --rm -it alpine chroot /mnt /bin/sh), lo que concede acceso total al sistema de archivos sin solicitar contraseña ni registrarse en sudo. Este riesgo no aplica si Docker está configurado en modo rootless (ver apartado 6.2), ya que en ese caso no se emplea el grupo del sistema y las operaciones quedan contenidas en el espacio de nombres del usuario.

lxd / incus-admin

Concede control sobre el demonio de contenedores a través de su socket local. Permite crear contenedores privilegiados (security.privileged=true) y montar el sistema de archivos del anfitrión en el contenedor. En Incus, el grupo administrativo es incus-admin, mientras que el grupo incus está restringido a proyectos delegados.

disk

Otorga acceso directo de lectura y escritura a los dispositivos de almacenamiento en bloque (/dev/sd*, /dev/nvme*, /dev/vd*). Permite eludir todos los permisos DAC del sistema de archivos, leer cualquier dato en crudo o alterar particiones mediante utilidades como debugfs.

staff

En Debian, /usr/local y sus subdirectorios pertenecen a root:staff con modo 2775, de modo que el grupo staff puede escribir en /usr/local/bin y /usr/local/sbin. En Ubuntu 24.04 esos directorios pertenecen a root:root con modo 755, por lo que el grupo no concede escritura salvo que se haya modificado. Compruébelo con ls -ld /usr/local/bin. Cuando existe esa escritura, dado que estas rutas suelen figurar antes que /usr/bin en la variable PATH del superusuario, un miembro de este grupo puede suplantar binarios del sistema para que root los ejecute inadvertidamente.

5.2.2. Grupos con acceso a información confidencial y auditoría

Estos grupos no permiten la ejecución directa de comandos administrativos, pero exponen datos sensibles que comprometen la confidencialidad del sistema:

Grupo Información expuesta y riesgo operacional

shadow

Permite la lectura de /etc/shadow y /etc/gshadow. Expone los hashes de las contraseñas de todas las cuentas del sistema, facilitando ataques de descifrado fuera de línea (offline cracking).

adm

Otorga permisos de lectura sobre los archivos de registro tradicionales en /var/log (como syslog o auth.log). En Ubuntu, una ACL sobre /var/log/journal le permite además leer el diario de systemd con journalctl. Puede revelar información sensible, direcciones IP de origen, nombres de cuenta o credenciales registradas accidentalmente por aplicaciones.

systemd-journal

Permite consultar la totalidad de los registros del diario de systemd mediante journalctl, exponiendo eventos de auditoría y mensajes de los servicios del sistema.

input

Concede acceso de lectura a los dispositivos de eventos en /dev/input/event*, lo que permite capturar eventos de teclado a modo de keylogger local para interceptar credenciales en texto plano.

Alternativa segura al grupo docker: adopción de Podman o modo rootless

Añadir una cuenta de usuario al grupo del sistema docker en su arquitectura tradicional (rootful) equivale a concederle privilegios absolutos de superusuario sin control ni registro en las políticas de auditoría de sudo. Dado que el demonio dockerd se ejecuta con privilegios de root y escucha en /var/run/docker.sock, cualquier miembro de dicho grupo puede desplegar un contenedor privilegiado y montar la raíz del sistema de archivos del anfitrión.

Para mitigar este vector crítico en entornos donde los usuarios deban ejecutar contenedores, existen dos soluciones de bastionado:

  1. Adopción de Podman: Diseñado con una arquitectura sin demonio (daemonless), Podman ejecuta los contenedores directamente como procesos subordinados al usuario que los invoca, prescindiendo de sockets con privilegios de root y apoyándose de forma nativa en los espacios de nombres de usuario configurados en /etc/subuid y /etc/subgid. No requiere que el usuario pertenezca a ningún grupo especial, eliminando de raíz la superficie de escalada de privilegios.

  2. Docker en modo rootless: Reconfigura el demonio de Docker para que se ejecute en el espacio de usuario (ver apartado 6.2), evitando el uso del grupo docker del sistema.


5.3. Archivos de configuración y visudo

sudo decide quién puede ejecutar qué, y como quién, leyendo un conjunto de reglas que se guardan en /etc/sudoers y en el directorio /etc/sudoers.d/. Como un error en estos archivos puede dejar sin acceso administrativo al sistema, se modifican siempre con visudo.

  • /etc/sudoers: Archivo de configuración principal. Nunca se debe editar con un editor de texto convencional, sino mediante sudo visudo, el cual bloquea el archivo para evitar concurrencia y valida la sintaxis antes de guardar.

  • /etc/sudoers.d/: Directorio para reglas modulares en archivos independientes. Es la práctica recomendada porque facilita la automatización y previene sobrescrituras durante las actualizaciones de paquetes. Se edita con sudo visudo -f, por ejemplo: sudo visudo -f /etc/sudoers.d/10-soporte. Los archivos se procesan por orden alfabético, por eso se usan prefijos numéricos con la misma cantidad de dígitos, como 10-soporte y 90-cloud-init-users. Además, sudo ignora los archivos cuyo nombre contiene un punto o termina en ~, de modo que una regla guardada como soporte.conf no se aplica, y un archivo nuevo debe tener modo 0440, que se fija con sudo chmod 440.

La sintaxis de una directiva es la siguiente:

quién dónde=(como_quién) qué_comandos
Campo Significado Ejemplos

quién

Usuario o grupo al que se aplica la regla. Un grupo se escribe con el prefijo %

maria, %soporte

dónde

Equipo en el que se evalúa la regla, no desde el que se conecta el usuario. ALL equivale a cualquier equipo. Solo se restringe cuando un mismo archivo sudoers se comparte entre varios equipos

ALL, web01, web02

como_quién

Usuario, y opcionalmente grupo, con cuya identidad se ejecutan las órdenes. Si se omite, es root

(root), (ALL), (maria:soporte)

qué_comandos

Órdenes permitidas, con la ruta completa y sus argumentos. Se pueden separar varias con comas

/usr/bin/id, /usr/bin/id, /usr/bin/whoami

Ejemplo de delegación con mínimo privilegio

En este ejemplo se define una regla que permite a los miembros del grupo soporte reiniciar el servicio SSH de Debian y Ubuntu, solicitándoles su propia contraseña, sin concederles ningún otro permiso de root:

%soporte ALL=(root) /usr/bin/systemctl restart ssh
Elemento Campo Significado

%soporte

quién

Grupo soporte. El signo % indica que es un grupo. Sin él, sería un usuario

ALL

dónde

Equipos en los que se aplica la regla. ALL significa en todos

(root)

como_quién

La orden se ejecuta con los privilegios de root. Es el valor por defecto si se omite, pero se escribe para que la regla sea explícita

/usr/bin/systemctl restart ssh

qué_comandos

Orden permitida, con su ruta completa y sus argumentos. Al fijar los argumentos, solo se permite exactamente esa combinación: systemctl stop ssh o systemctl restart cron quedan denegados

Para comprobar la regla una vez instalada, sudo visudo -c valida la sintaxis de todos los archivos y sudo -l -U usuario muestra los privilegios que recibe un miembro de soporte.

Cómo se combinan varias reglas: un ejemplo real

Una cuenta suele recibir privilegios de varias reglas a la vez y sudo -l muestra el resultado combinado. En una imagen de Ubuntu para entornos de nube, como las que usa OpenStack, la cuenta ubuntu produce esta salida:

    (ALL : ALL) ALL
    (ALL) NOPASSWD: ALL
Línea de la salida Origen Significado

(ALL : ALL) ALL

%sudo ALL=(ALL:ALL) ALL, en /etc/sudoers

Como ubuntu pertenece al grupo sudo, puede ejecutar cualquier orden como cualquier usuario y grupo, indicados en el formato (usuario : grupo). Esta regla pide su contraseña

(ALL) NOPASSWD: ALL

ubuntu ALL=(ALL) NOPASSWD:ALL, en /etc/sudoers.d/90-cloud-init-users

Puede ejecutar cualquier orden como cualquier usuario sin contraseña

Cuando varias reglas coinciden, sudo aplica la última que encaja, de modo que la regla con NOPASSWD: prevalece y ubuntu obtiene root sin que se le pida ninguna credencial. Es una configuración aceptable en una máquina virtual de laboratorio, donde ubuntu es la cuenta administrativa de la imagen, pero en un servidor real elimina la barrera descrita en el siguiente aviso.

Configuraciones peligrosas en sudoers

  • NOPASSWD: Suprime la solicitud de contraseña. Si la sesión del usuario se ve comprometida, el atacante obtiene root inmediatamente.

  • Binarios con escape a intérprete de comandos: Conceder permisos sudo sobre herramientas como vim, less, find, awk, tar o python equivale a otorgar una shell de root, ya que todas disponen de comandos internos para invocar intérpretes interactivos. El proyecto GTFOBins documenta cientos de binarios con estas características.

  • Uso de comodines (*) en argumentos: En los argumentos de una regla, el * encaja con cualquier texto, incluidas las barras, los .. y los espacios, por lo que el usuario puede añadir rutas o argumentos que la regla no pretendía permitir. Por ejemplo, la regla usuario ALL=(root) /usr/bin/cat /var/log/* parece limitar la lectura a los registros, pero sudo cat /var/log/../../etc/shadow o sudo cat /var/log/syslog /etc/shadow muestran /etc/shadow como root. Para evitarlo, se deben fijar las rutas y los argumentos exactos, como en /usr/bin/systemctl restart ssh, o conceder la lectura de registros mediante un grupo como adm en lugar de sudo.

Demostración

Puede comprobar este riesgo de forma práctica en la demostración de escalada de privilegios con sudo y GTFOBins, que reproduce el escape a una shell de root a partir de una regla sudo mal configurada y detalla cómo detectarlo y mitigarlo.


5.4. Comandos de auditoría y trazabilidad

Comando Utilidad técnica

sudo -l

Lista los comandos que el usuario actual puede invocar mediante sudo.

sudo -l -U usuario

Permite al administrador inspeccionar los privilegios concedidos a otra cuenta.

sudo visudo -c

Verifica la integridad sintáctica de /etc/sudoers y de /etc/sudoers.d/*. -c es check.

journalctl _COMM=sudo

Muestra el registro de todos los comandos ejecutados a través de sudo. journalctl consulta el diario de systemd y _COMM=sudo filtra por el programa que generó cada mensaje.

Con los conceptos de privilegios administrativos, reglas de sudoers y riesgos de grupos privilegiados, ya puede realizar:

6. Mecanismos avanzados y resolución de identidades

Una vez asimilada la administración cotidiana de usuarios y grupos locales, resulta indispensable comprender los mecanismos de arquitectura interna que gobiernan la criptografía de contraseñas, la virtualización sin privilegios y la integración con directorios empresariales.


6.1. Criptografía avanzada de contraseñas: yescrypt

A lo largo de la historia de los sistemas UNIX y Linux, los algoritmos de almacenamiento de credenciales han evolucionado para contrarrestar el incremento exponencial en la capacidad de cómputo de los atacantes:

\[\text{DES} \longrightarrow \text{MD5 (\$1\$)} \longrightarrow \text{SHA-256 (\$5\$)} \longrightarrow \text{SHA-512 (\$6\$)} \longrightarrow \text{yescrypt (\$y\$)}\]

En sistemas modernos como Debian 11, Debian 12 (Bookworm), Ubuntu 22.04 LTS y versiones recientes de Fedora, el algoritmo predeterminado es yescrypt (prefijo $y$).

6.1.1. Anatomía de una contraseña yescrypt

$y$j9T$WOMmh5En0h210kQG0eK...$bK8kU0oG10Wb0X1z9V4f6D...    (1) (2) (3) (4)
1 Identificador del algoritmo ($y$ identifica yescrypt).
2 Parámetros de configuración y dificultad (cost settings).
3 Sal criptográfica aleatoria que individualiza el hash.
4 Hash final derivado tras aplicar la función criptográfica.
Parámetros de coste (j9T)

La cadena j9T codifica los parámetros de configuración: j selecciona el modo estándar recomendado con memoria de lectura y escritura, 9 fija un coste \(N = 4096\) y T un tamaño de bloque \(r = 32\).

6.1.2. Funciones resistentes a memoria (Memory-Hard)

Los algoritmos tradicionales como SHA-512 son muy rápidos y casi no demandan memoria RAM, lo que beneficia al atacante: una GPU o un ASIC calcula miles de millones de hashes por segundo. yescrypt es una función memory-hard: cada verificación exige un búfer de \(128 \times r \times N = 16.777.216\) bytes, es decir, unos 16 MiB. Para un usuario que inicia sesión es imperceptible, pero para un atacante que evalúa millones de combinaciones satura la memoria y el ancho de banda de los aceleradores, y elimina su ventaja económica.

6.1.3. Configuración de yescrypt en el sistema

El algoritmo de hash del sistema se gestiona en dos ubicaciones complementarias:

  1. En PAM (/etc/pam.d/common-password en Debian y Ubuntu): Se configura mediante una opción del módulo pam_unix.so. Es la directiva prioritaria utilizada por el comando passwd en las operaciones interactivas cotidianas:

    password [success=1 default=ignore] pam_unix.so obscure yescrypt
  2. En /etc/login.defs: Fija el algoritmo para las herramientas que no delegan en PAM. En Debian y Ubuntu, passwd, chpasswd y newusers sí lo hacen, de modo que el valor de PAM prevalece sobre ENCRYPT_METHOD. En Ubuntu 24.04, con ENCRYPT_METHOD SHA512 en /etc/login.defs, tanto chpasswd como newusers generan hashes $y$. Para fijar otro algoritmo en una ejecución concreta, chpasswd admite la opción -c, por ejemplo chpasswd -c SHA512. Una configuración coherente es:

    ENCRYPT_METHOD YESCRYPT
    YESCRYPT_COST_FACTOR 5

    La directiva YESCRYPT_COST_FACTOR permite graduar el coste entre los niveles 1 y 11, siendo 5 el valor que se aplica si no se especifica. En Ubuntu 24.04 aparece comentada en /etc/login.defs, y el sistema usa ese valor implícito.

La modificación del algoritmo o del factor de coste no altera retroactivamente las contraseñas preexistentes en /etc/shadow. Cada registro conservará su algoritmo original hasta que el usuario realice un nuevo cambio de contraseña, momento en el cual el sistema recalculará y almacenará el hash conforme a la nueva directiva configurada.

6.1.4. Detección y migración de algoritmos heredados (Legacy)

En auditorías de bastionado sobre servidores actualizados a lo largo del tiempo o procedentes de migraciones anteriores, es muy frecuente encontrar cuentas cuyas contraseñas continúan almacenadas con algoritmos obsoletos o vulnerables, tales como MD5 ($1$), SHA-256 ($5$) o SHA-512 sin parámetros de memoria ($6$).

Dado que la actualización de las directivas en PAM o en /etc/login.defs para activar yescrypt no recalcula automáticamente los registros existentes en /etc/shadow, el administrador debe identificar activamente estas cuentas y forzar su renovación controlada.

Auditoría de contraseñas con algoritmos heredados

Para auditar e identificar qué cuentas del sistema utilizan funciones de hashing previas a yescrypt, se puede filtrar /etc/shadow por los prefijos de los algoritmos clásicos:

# Listar usuarios con hashes MD5 ($1$), SHA-256 ($5$) o SHA-512 ($6$)
sudo awk -F: '$2 ~ /^\$([156])\$/ {print $1, substr($2,1,3)}' /etc/shadow

Es el mismo esquema que en la auditoría de cuentas bloqueadas con otro patrón:

Elemento Significado

-F:

Usa los dos puntos como separador de campos

$2 ~ /^\$([156])\$/

Selecciona los registros cuyo segundo campo, el hash, empieza por $1$, $5$ o $6$. ^ indica el inicio, \$ es un signo $ literal y [156] admite cualquiera de esas tres cifras

print $1, substr($2,1,3)

Muestra el nombre de la cuenta y los tres primeros caracteres del hash, es decir, el prefijo que identifica el algoritmo. substr($2,1,3) extrae 3 caracteres del campo $2 a partir de la posición 1

Procedimiento de remediación y rotación forzada

Para garantizar una transición segura hacia algoritmos modernos, se aplican dos procedimientos según el tipo de cuenta:

  1. Cuentas interactivas de usuarios:
    La estrategia más segura consiste en marcar la contraseña como caducada forzando su actualización en el siguiente inicio de sesión:

    sudo chage -d 0 maria

    Cuando la usuaria inicie sesión, la pila PAM interceptará la solicitud a través de pam_unix.so, validará la credencial actual y exigirá introducir una nueva contraseña, la cual será procesada y almacenada bajo el algoritmo configurado en ese momento (yescrypt con su sal correspondiente).

    Para automatizar este requisito sobre la totalidad de cuentas identificadas con algoritmos antiguos:

    for usuario in $(sudo awk -F: '$2 ~ /^\$([156])\$/ {print $1}' /etc/shadow); do
        sudo chage -d 0 "$usuario"
    done
    Elemento Función

    for usuario in …​; do …​; done

    Repite la orden chage para cada nombre de la lista

    $(…​)

    Ejecuta el awk y sustituye la expresión por su salida, que es la lista de cuentas afectadas

    usuario

    Variable que toma uno de esos nombres en cada vuelta

    chage -d 0

    Fija la fecha del último cambio en 0 (date), lo que obliga a cambiar la contraseña en el siguiente inicio de sesión

  2. Cuentas de servicio o despliegues automatizados:
    En entornos desatendidos donde se dispone de las contraseñas gestionadas de forma centralizada, se puede actualizar la clave de forma masiva con chpasswd, la cual aplicará inmediatamente el algoritmo configurado en PAM, es decir, yescrypt en las distribuciones actuales:

    echo "servicio_backup:ClaveComplejaGenerada2026!" | sudo chpasswd
    Elemento Función

    chpasswd

    Lee de la entrada estándar líneas con el formato usuario:contraseña y establece esas contraseñas

    echo "…​" | sudo chpasswd

    La tubería | alimenta a chpasswd con la salida de echo

    La cuenta debe existir previamente, porque en caso contrario chpasswd no aplica ningún cambio. Para verificar el resultado, compruebe que el prefijo es $y$:

    sudo grep '^servicio_backup:' /etc/shadow | cut -d: -f2 | cut -c1-3

6.2. Contenedores sin privilegios: /etc/subuid y /etc/subgid (Rootless)

En distribuciones modernas, al dar de alta un usuario normal se generan automáticamente entradas en los archivos /etc/subuid y /etc/subgid:

maria:100000:65536

Formato del registro:

usuario:UID_INICIAL:CANTIDAD

Esto indica que a la usuaria maria se le asigna un rango de 65.536 identificadores subordinados a partir del UID 100000. useradd reparte estos rangos de forma consecutiva según las variables SUB_UID_MIN, SUB_UID_MAX y SUB_UID_COUNT de /etc/login.defs, y sus equivalentes SUB_GID_*. En Ubuntu 24.04 empiezan en 100000 y asignan 65.536 identificadores a cada cuenta.

6.2.1. Propósito de seguridad

Estos archivos habilitan los espacios de nombres de usuario (User Namespaces) para tecnologías de contenedores sin privilegios (Rootless Docker o Podman):

  • El usuario puede actuar como root (UID 0) dentro del contenedor.

  • En el sistema anfitrión real, todos sus procesos se ejecutan bajo su UID subordinado sin privilegios (ej. UID 100000).

Si un atacante logra escapar del contenedor, aterriza en el anfitrión como un usuario sin privilegios y no como root, impidiendo la toma del sistema físico.

6.2.2. Verificación y auditoría

Para consultar el rango asignado a una cuenta:

grep '^maria:' /etc/subuid /etc/subgid

Al indicar dos archivos, grep antepone a cada resultado el nombre del archivo en el que lo encontró, de modo que se ven los dos rangos a la vez.

userdel elimina las entradas de la cuenta, pero usermod -l no las renombra: el rango sigue asociado al nombre antiguo y queda huérfano cuando la cuenta se elimina con su nuevo nombre. Si después se crea otra cuenta con ese nombre, useradd le asigna un rango nuevo, pero la entrada antigua sigue a su nombre, por lo que la cuenta nueva recibe también el rango anterior y puede acceder a los archivos que dejaron los contenedores de la cuenta eliminada. Para detectar entradas cuyo usuario ya no existe:

for f in /etc/subuid /etc/subgid; do
    cut -d: -f1 "$f" | while read -r u; do
        getent passwd "$u" >/dev/null || echo "$f: $u no existe"
    done
done
Elemento Función

for f in …​

Repite la comprobación para los dos archivos

cut -d: -f1 "$f"

Extrae el primer campo de cada línea, el nombre de la cuenta

while read -r u

Lee esos nombres uno a uno en la variable u

getent passwd "$u" >/dev/null

Busca la cuenta y descarta la salida, porque solo interesa si existe

|| echo …​

Si getent no la encuentra, muestra el archivo y el nombre huérfano

La salida debe estar vacía. Las entradas huérfanas se eliminan editando ambos archivos como root.

Ubuntu 24.04 añade una protección adicional: con kernel.apparmor_restrict_unprivileged_userns = 1, un usuario sin privilegios solo puede crear espacios de nombres de usuario con los programas que tienen un perfil de AppArmor que lo permite, como los motores de contenedores. Una orden como unshare --user --map-root-user falla con «Operation not permitted». El valor se consulta con sysctl kernel.apparmor_restrict_unprivileged_userns.


6.3. Fuentes de identidades híbridas: NSS y getent

Los archivos /etc/passwd y /etc/group representan la base de identidades local, pero no la única. En redes corporativas, los usuarios y grupos proceden habitualmente de directorios centralizados como LDAP, FreeIPA o Active Directory. El servicio que conecta el sistema con ellos es el System Security Services Daemon (SSSD), que consulta el directorio remoto, guarda en caché las respuestas y se las entrega a NSS como si fueran una fuente local más.

El NSS (Name Service Switch) es el mecanismo de las bibliotecas del sistema que permite a los programas obtener información de nombres, como usuarios, grupos o equipos, sin saber de dónde procede. Cuando un programa consulta una cuenta, NSS recorre las fuentes configuradas en /etc/nsswitch.conf, en el orden indicado, hasta encontrar una respuesta:

passwd:         files systemd sss
group:          files systemd sss
shadow:         files sss

Cada línea asocia una base de datos con una lista ordenada de fuentes:

Elemento Significado

passwd, group, shadow

Base de datos que se consulta: cuentas, grupos y contraseñas

files

Archivos locales, como /etc/passwd y /etc/group. Es la primera fuente

systemd

Servicios dinámicos de systemd, que proporcionan cuentas que no están en ningún archivo, como las de los usuarios dinámicos de servicios

sss

SSSD, la última fuente. Solo aparece cuando SSSD está instalado y configurado: en un Ubuntu 24.04 que no pertenece a un dominio, la línea es passwd: files systemd

La búsqueda se detiene en la primera fuente que responde, por lo que una cuenta local prevalece sobre una del directorio con el mismo nombre.

Arquitectura de resolución de identidades: Name Service Switch (NSS) y getent
Figura 2. Arquitectura de resolución de identidades: Name Service Switch (NSS) y getent

El comando getent (get entries) muestra las entradas de las bases de datos soportadas por las bibliotecas NSS. Consulta las mismas fuentes y en el mismo orden que cualquier otro programa del sistema, por lo que devuelve la misma respuesta que recibiría, por ejemplo, el proceso de inicio de sesión. Por este motivo, al auditar cuentas debe emplearse en lugar de leer directamente los archivos planos:

getent passwd maria
getent group sudo
Orden Resultado

getent passwd maria

La entrada de maria en la base de datos de cuentas, venga de /etc/passwd o de un directorio en red

getent group sudo

La entrada del grupo sudo con sus miembros

getent passwd

Sin clave, todas las entradas de la base de datos, salvo que esta no admita enumeración

Un grep sobre /etc/passwd omitiría cualquier usuario procedente de un directorio empresarial en red, mientras que getent consulta a través de la capa NSS completa.

De la identidad a la autenticación: PAM

NSS solo proporciona los datos de las cuentas. La decisión de conceder o denegar el acceso la toma PAM (Pluggable Authentication Modules), que consulta ese almacén y evalúa las políticas configuradas:

Pasarela de autenticación: Interacción entre la pila PAM y /etc/shadow
Figura 3. Pasarela de autenticación: Interacción entre la pila PAM y /etc/shadow

En la fase auth, pam_unix.so comprueba el hash del campo 2 de /etc/shadow. En la fase account, evalúa los campos 4 a 8 y rechaza el acceso si la cuenta ha caducado, también con una clave SSH. Por eso passwd -l solo afecta a la primera fase y usermod -L -e 1 actúa sobre la segunda, como se explicó en el apartado 3.6. La estructura de las pilas y el bastionado con pam_pwquality y pam_faillock se estudian en la guía de módulos de autenticación conectables (PAM).

Con los conceptos de criptografía de contraseñas y algoritmos heredados de este capítulo, puede repasar:

7. Guía consolidada de bastionado y lista de verificación

Como síntesis de las medidas analizadas en los capítulos anteriores, el administrador de sistemas debe verificar de forma sistemática el siguiente catálogo de directivas técnicas de endurecimiento.


7.1. Matriz de riesgos y medidas técnicas

Vector de amenaza Impacto potencial Medida de bastionado obligatoria Dónde se verifica

Cuenta clonada con UID 0

Puerta trasera de administración completa

Exigir unicidad absoluta de UID 0 para root

Punto 1 de 7.2

Cuentas sin contraseña

Acceso interactivo local no autenticado

Bloquear o asignar contraseñas robustas

Punto 4 de 7.2

Permisos laxos en /home

Fuga de privacidad entre usuarios normales

Imponer los permisos 0750 o 0700 que recomienda el CIS

Apartado 3.3.3

Acceso SSH con clave tras bloquear la contraseña

Persistencia tras deshabilitar la contraseña

Bloqueo completo de cuenta con expiración

Apartado 3.6.1

Terminales desatendidas

Acceso físico o lateral no autorizado

Cierre forzado de shell por inactividad

Punto 3 de 7.2

Pertenencia a docker

Escalada a superusuario sin auditoría

Migrar a Docker rootless o Podman

Apartado 5.2

Archivos huérfanos postbaja

Apropiación de archivos por nuevo UID

Rastrear huérfanos antes de reasignar UIDs

Apartado 3.6.2


7.2. Lista de verificación de bastionado (Checklist CIS)

  1. Asegurar que únicamente root tenga UID 0 y remediar cuentas clandestinas:

    awk -F: '$3 == 0 {print $1}' /etc/passwd
    Elemento Significado

    awk

    Procesa el archivo línea a línea

    -F:

    Usa los dos puntos como separador de campos

    $3 == 0

    Selecciona las líneas cuyo tercer campo, el UID, vale 0

    {print $1}

    Muestra el primer campo, el nombre de la cuenta

    La salida debe devolver únicamente root. Si aparece cualquier otra cuenta (por ejemplo toor o admin), el sistema contiene una puerta trasera con privilegios absolutos de administración.

    Precaución operacional al eliminar cuentas con UID 0

    Una cuenta clandestina con UID 0 comparte identidad con root a efectos del núcleo, y eso condiciona toda la remediación. Para llevarla a cabo de forma segura:

    1. Bloquear la cuenta preventivamente: Bloquear la contraseña y hacer caducar la cuenta mientras se analiza el incidente. La orden actúa solo sobre la entrada toor de /etc/shadow:

      sudo usermod -L -e 1 toor
    2. Interrumpir sus sesiones sin afectar a root: Localizar las sesiones abiertas con el nombre de la cuenta clandestina y terminar únicamente los procesos de esa terminal:

      who | grep toor
      sudo pkill -t pts/1
      Orden Función

      who

      Lista las sesiones y su terminal, como pts/1

      pkill -t pts/1

      Termina los procesos asociados a esa terminal, porque -t (terminal) los selecciona por terminal en lugar de por usuario

      No seleccione procesos por nombre de usuario. Como toor y root tienen el mismo UID, pkill -u toor y pkill -9 -u toor apuntan a todos los procesos de root, incluido systemd con PID 1, y pueden dejar el sistema inutilizable. En una comprobación realizada con pgrep -u toor sobre Ubuntu 24.04, la orden devolvió exactamente los mismos procesos que pgrep -u root. Del mismo modo, loginctl terminate-user toor cerraría todas las sesiones de root.

    3. Eliminar la cuenta sin tocar el directorio raíz: Ejecutar sudo userdel -f toor, donde -f (force) fuerza el borrado aunque la cuenta tenga procesos activos. Sin la opción -f, userdel se niega a actuar con el mensaje user toor is currently used by process 1, porque todos los procesos de root cuentan como suyos. Con -f el mensaje se sigue mostrando como aviso, pero la cuenta se elimina, lo que se comprueba con getent passwd toor. Bajo ninguna circunstancia utilice la bandera -r (userdel -r), puesto que si la cuenta compartía el directorio /root con el superusuario legítimo, eliminaría el directorio de trabajo del administrador real.

  2. Desactivar el intérprete interactivo en cuentas de servicio: Las cuentas de sistema, con UID entre 1 y 999, deben utilizar como shell /usr/sbin/nologin o /bin/false, que impiden la sesión interactiva:

    awk -F: '$3 > 0 && $3 < 1000 && $7 !~ /(nologin|false)$/ {print $1, $7}' /etc/passwd
    Elemento Significado

    $3 > 0 && $3 < 1000

    Selecciona las cuentas de sistema, excluyendo a root

    $7 !~ /(nologin|false)$/

    Descarta las que tienen como shell nologin o false

    {print $1, $7}

    Muestra el nombre de la cuenta y su shell

    En Debian y Ubuntu, la única línea esperada es sync /bin/sync. La cuenta sync es una excepción histórica: su shell ejecuta la orden sync y termina, sin ofrecer una sesión interactiva.

  3. Configurar el cierre automático de sesión por inactividad (TMOUT): Para evitar que una terminal desatendida quede expuesta, se define el cierre automático a los 15 minutos (900 segundos) de inactividad en /etc/profile.d/timeout.sh, que se aplica a todas las sesiones de login:

    sudo tee /etc/profile.d/timeout.sh << 'EOF'
    readonly TMOUT=900
    export TMOUT
    EOF
    sudo chmod 644 /etc/profile.d/timeout.sh
    Elemento Significado

    sudo tee archivo << 'EOF'

    tee escribe en un archivo lo que recibe. Se usa con sudo porque la redirección > no hereda los privilegios. << 'EOF' indica que el texto que sigue, hasta la línea EOF, es la entrada

    readonly TMOUT=900

    TMOUT es el número de segundos de inactividad tras los cuales la shell se cierra. readonly impide que el usuario lo modifique o lo elimine

    export TMOUT

    Hace que la variable sea visible para los programas que se lancen desde la shell

    readonly solo protege la variable en la shell que lee el archivo. El atributo no se hereda, por lo que el usuario puede abrir otra shell con bash y ejecutar en ella unset TMOUT, y la orden funciona. TMOUT es, por tanto, una medida disuasoria y no un control que el usuario no pueda eludir. Para un cierre que dependa del sistema y no de la shell, systemd-logind permite detener las sesiones inactivas con la directiva StopIdleSessionSec de /etc/systemd/logind.conf, desactivada por defecto en Ubuntu 24.04.

  4. Identificar cuentas con contraseña vacía:

    sudo awk -F: '$2 == "" {print $1}' /etc/shadow
    Elemento Significado

    $2 == ""

    Selecciona las cuentas cuyo segundo campo, el hash, está vacío

    {print $1}

    Muestra el nombre de la cuenta

    La salida debe ser estrictamente vacía.

  5. Auditar identificadores duplicados (UIDs y GIDs):

    cut -d: -f3 /etc/passwd | sort -n | uniq -d
    cut -d: -f3 /etc/group | sort -n | uniq -d

    Tres órdenes encadenadas con tuberías:

    Orden Significado

    cut -d: -f3

    cut extrae columnas. -d: fija los dos puntos como delimitador y -f3 (field) selecciona el tercer campo. Con -f1 se obtienen los nombres

    sort -n

    Ordena las líneas. -n lo hace de forma numérica

    uniq -d

    Muestra solo las líneas repetidas (duplicated). Necesita la entrada ordenada. La salida debe estar vacía

  6. Auditar nombres duplicados de usuario y grupo:

    cut -d: -f1 /etc/passwd | sort | uniq -d
    cut -d: -f1 /etc/group | sort | uniq -d
  7. Elevación segura con su -: Al cambiar de usuario, utilice siempre su - en lugar de su, y para obtener una shell de superusuario, sudo -i. El guion inicializa un entorno de inicio de sesión limpio y evita heredar variables manipuladas o rutas relativas en el PATH. En Ubuntu, la contraseña de root está bloqueada, por lo que su - root falla con «Authentication failure» y sudo -i es la forma habitual de abrir una sesión de root.

  8. Auditar archivos de inicio ocultos y eliminar archivos peligrosos:

    • Comprobar que los archivos de inicio (.bashrc, .profile) en /home no tengan permisos de escritura para el grupo ni para otros:

      sudo find /home -maxdepth 2 -name ".*" -perm /022 -ls
      Elemento Significado

      -maxdepth 2

      Desciende hasta dos niveles, de modo que revisa los archivos dentro de cada directorio personal

      -name ".*"

      Selecciona los nombres que empiezan por punto, es decir, los ocultos

      -perm /022

      Selecciona los que tienen escritura para el grupo o para otros

    • Asegurar que no existan archivos de credenciales obsoletos o inseguros:

      sudo find /home \( -name ".netrc" -o -name ".rhosts" -o -name ".forward" \) -ls
      Elemento Significado

      -o

      Significa «o»

      \( …​ \)

      Agrupan los tres nombres de archivo

  9. Verificar que el grupo shadow no tenga miembros interactivos:

    grep '^shadow:' /etc/group
    Elemento Significado

    '^shadow:'

    Selecciona la línea que empieza por shadow:

    El cuarto campo debe estar vacío. Si contiene usuarios, estos pueden leer los hashes sin necesidad de sudo. Esa lista solo incluye a los miembros secundarios, por lo que también hay que comprobar que ninguna cuenta tenga shadow como grupo principal:

    awk -F: -v gid="$(getent group shadow | cut -d: -f3)" '$4 == gid {print $1}' /etc/passwd
    Elemento Significado

    getent group shadow | cut -d: -f3

    Obtiene el GID del grupo shadow, que en Debian y Ubuntu es 42

    -v gid="…​"

    Guarda ese GID en la variable gid de awk

    $4 == gid

    Selecciona las cuentas cuyo cuarto campo, el grupo principal, es shadow

    La salida debe estar vacía.

  10. Proteger la cuenta root: En sistemas administrados con sudo, la contraseña de root debe permanecer bloqueada y su grupo principal debe ser el GID 0:

    sudo passwd -S root
    awk -F: '$1 == "root" {print $4}' /etc/passwd

    La primera orden debe mostrar el estado L y la segunda, el valor 0.


7.3. Diagnóstico automatizado de integridad: pwck y grpck

Las utilidades pwck y grpck analizan la integridad sintáctica y referencial de los archivos de cuentas. Es imprescindible ejecutarlas en modo de solo lectura (-r) en tareas de auditoría para no aplicar cambios imprevistos en los archivos del sistema:

sudo pwck -r
sudo grpck -r
Elemento Función

pwck

Verifica /etc/passwd y /etc/shadow

grpck

Verifica /etc/group y /etc/gshadow

-r

Las ejecuta en solo lectura (read-only)

Estas herramientas comprueban que no existan campos omitidos, delimitadores faltantes, directorios personales inexistentes, formatos corruptos ni GIDs inexistentes asignados a usuarios. En Ubuntu 24.04, pwck -r muestra siempre avisos sobre los directorios inexistentes de cuentas del sistema como lp o www-data, que son normales, como se explica en el apartado 2.2.

Una vez estudiadas todas las medidas de bastionado del ciclo de vida de usuarios y grupos, puede consolidar sus competencias completando:

8. Ejercicios prácticos

Los ejercicios están diseñados para realizarse en orden sobre una máquina virtual Ubuntu/Debian de pruebas, ya que algunos reutilizan usuarios y grupos creados en ejercicios anteriores. El último ejercicio deja el sistema en su estado original.

No realice estos ejercicios en un servidor en producción. Algunos pasos simulan configuraciones inseguras de forma deliberada.

Nº Ejercicio Competencia que desarrolla Dificultad

1

Exploración de los archivos de cuentas

Interpretar passwd, shadow y group, sus permisos y su relación

Baja

2

Hash y sal de las contraseñas

Comprender cómo se almacenan las contraseñas y el papel de la sal

Media

3

Alta segura de cuentas interactivas y de servicio

Crear cuentas con los atributos adecuados a su función

Media

4

Valores por defecto: login.defs, useradd -D y /etc/skel

Configurar cómo nacen las nuevas cuentas

Media

5

Modificación y renombrado de cuentas

Gestionar cambios en cuentas existentes sin inconsistencias

Media

6

Caducidad de contraseñas y cuentas temporales

Aplicar políticas de caducidad, expiración e inactividad

Media

7

Bloqueo parcial frente a bloqueo completo

Diferenciar el bloqueo de contraseña del bloqueo real de la cuenta

Media

8

Baja segura y reutilización de UID

Eliminar cuentas sin dejar riesgos residuales

Media

9

Grupos, gpasswd y directorio compartido

Organizar usuarios por funciones y delegar la gestión de grupos

Media

10

Detección de una puerta trasera con UID 0

Identificar técnicas de persistencia basadas en cuentas

Alta

11

Auditoría de grupos privilegiados y sudo

Detectar privilegios excesivos y delegar con mínimo privilegio

Alta

12

Controles CIS y script de auditoría

Automatizar la verificación del bastionado de cuentas

Alta

13

Limpieza del entorno

Revertir los cambios realizados durante la práctica

Baja

8.1. Ejercicio 1. Exploración de los archivos de cuentas

En un sistema multiusuario, la seguridad comienza por conocer quién existe en el sistema, qué privilegios tiene cada cuenta y cómo se protege su información.

Realice los siguientes pasos:

  1. Muestra las primeras 10 líneas del archivo /etc/passwd e identifica los siete campos de una de ellas. Use el comando head.

  2. Lista todos los usuarios que tengan un UID menor que 1000 junto con su shell asignado, que está en el séptimo campo del archivo /etc/passwd. Use el comando awk.

  3. Audita si existe alguna cuenta de sistema (UID entre 1 y 999) que disponga indebidamente de un shell interactivo (distinto de nologin, false o sync). Use el comando awk.

  4. Comprueba los permisos, propietario y grupo de /etc/passwd, /etc/shadow, /etc/group y /etc/gshadow, e interpreta el resultado.

  5. Intenta visualizar /etc/shadow sin privilegios de superusuario (deberías obtener “Permiso denegado”) y después con sudo.

  6. Identifica qué algoritmo de hash se ha usado para la contraseña de tu propio usuario, a partir del prefijo del segundo campo de /etc/shadow.

  7. Convierte el campo lastchange de tu usuario en una fecha legible.

  8. Muestra tu grupo principal y tus grupos secundarios, y comprueba que tu entrada se obtiene igual con grep que con getent. Explica en qué situación ambos comandos darían resultados distintos.


8.2. Ejercicio 2. Hash y sal de las contraseñas

Las contraseñas no se almacenan cifradas, sino como hash con sal. En este ejercicio comprobará experimentalmente para qué sirve la sal.

Realice los siguientes pasos:

  1. Genera dos veces el hash SHA-512 de la contraseña Bastionado2026 con el comando openssl passwd -6. ¿Qué hace el comando anterior? ¿Son iguales los resultados? ¿Por qué?

  2. Repite la operación fijando manualmente la sal abcdefgh. Usa el comando openssl passwd -6 -salt <sal> <password>. ¿Qué ocurre ahora?

  3. Instala el paquete whois y genera un hash yescrypt con mkpasswd. Identifica en el resultado el identificador del algoritmo, los parámetros de coste y la sal.

  4. Comprueba qué algoritmo utiliza el sistema para las nuevas contraseñas, tanto en PAM como en /etc/login.defs. ¿Cuál de los dos tiene prioridad al usar passwd?

  5. Explica por qué la sal impide que un atacante use tablas precalculadas (rainbow tables) y por qué yescrypt es más resistente que SHA-512 a los ataques con GPU.


8.3. Ejercicio 3. Alta segura de cuentas interactivas y de servicio

Cada cuenta debe crearse con los atributos adecuados a su función: una persona necesita una shell y un directorio personal, pero un servicio no.

Realice los siguientes pasos:

  1. Crea el usuario interactivo prueba1 con directorio personal, shell /bin/bash y el comentario Usuario de prueba.

  2. Comprueba qué contiene el campo de contraseña de prueba1 en /etc/shadow antes de asignarle una contraseña. ¿Puede iniciar sesión?

  3. Asígnale una contraseña con el comando passwd y obliga a que la cambie en su primer inicio de sesión con el comando chage.

  4. Inicia sesión como prueba1 con su - y verifica que el sistema obliga a cambiar la contraseña.

  5. Crea la cuenta de servicio appsvc como cuenta del sistema, sin directorio personal creado, con directorio /var/lib/appsvc y shell /usr/sbin/nologin.

  6. Comprueba que su UID está por debajo de 1000 y que no tiene grupo privado con UID mayor o igual que 1000.

  7. Verifica que la cuenta appsvc no permite una sesión interactiva, pero que sí puede ejecutar procesos (como haría un servicio).


8.4. Ejercicio 4. Valores por defecto: login.defs, useradd -D y /etc/skel

Garantizar que las nuevas cuentas se crean con una configuración segura es más eficaz que corregirlas una a una después.

El archivo /etc/login.defs define los valores por defecto que se aplican al crear una cuenta. Cada línea asocia el nombre de una variable con su valor. Las que se utilizan en este ejercicio son:

Variable Significado Valor en Ubuntu 24.04

PASS_MAX_DAYS

Días máximos de validez de la contraseña antes de que deba cambiarse

99999, es decir, no caduca

PASS_MIN_DAYS

Días mínimos que deben pasar entre dos cambios de contraseña

0, sin restricción

PASS_WARN_AGE

Días de antelación con los que se avisa de que la contraseña va a caducar

7

HOME_MODE

Permisos con los que se crea el directorio personal de las cuentas nuevas

0750

UMASK

Máscara de permisos para los archivos y directorios que crean las cuentas nuevas

022

ENCRYPT_METHOD

Algoritmo con el que se calcula el hash de la contraseña. En Ubuntu 24.04 la orden passwd lo decide pam_unix, que usa yescrypt

SHA512

Los parámetros PASS_* se copian a /etc/shadow en el momento de crear la cuenta: por eso no afectan a las cuentas que ya existían. La orden useradd -D muestra otros valores por defecto, como INACTIVE, que son los días de gracia tras caducar la contraseña antes de desactivar la cuenta. Estos conceptos se explican en los apartados 3.3 y 3.5 de este capítulo.

Realice los siguientes pasos:

  1. Haz una copia de seguridad de /etc/login.defs y de /etc/skel/.profile. Guarda la segunda fuera de /etc/skel, porque todo lo que contiene ese directorio se copia al directorio personal de cada cuenta nueva.

  2. Consulta los valores actuales de PASS_MAX_DAYS, PASS_MIN_DAYS, PASS_WARN_AGE, HOME_MODE, UMASK y ENCRYPT_METHOD.

  3. Modifica /etc/login.defs para que PASS_MAX_DAYS valga 365 y PASS_MIN_DAYS valga 1 (valores CIS). Si HOME_MODE no está definido, añade HOME_MODE 0750. Utilice el comando sed y tee.

  4. Consulta los valores por defecto de useradd y configura que las cuentas se desactiven 30 días después de caducar su contraseña.

  5. Inspecciona los archivos ocultos de /etc/skel y añade al final de /etc/skel/.profile la directiva umask 027. Con ella, las cuentas que se creen a partir de ahora abrirán sus sesiones con una máscara que hace que los archivos nuevos tengan permisos 640 y los directorios 750, de modo que el resto de usuarios no pueda acceder a ellos. Complementa a HOME_MODE, que solo protege el propio directorio personal en el momento de crearlo. Utilice el comando tee.

  6. Crea el usuario auditor y verifica: permisos de su directorio personal, su umask al iniciar sesión y su política de caducidad.

  7. Compara la salida de sudo chage -l auditor con la de sudo chage -l prueba1. ¿Por qué los cambios en login.defs no han afectado a prueba1?


8.5. Ejercicio 5. Modificación y renombrado de cuentas

En ocasiones es necesario ajustar cuentas existentes sin recrearlas, por ejemplo, al cambiar el nombre de un usuario. Hay que hacerlo con cuidado para no dejar inconsistencias.

Realice los siguientes pasos:

  1. Crea el usuario seguridad con directorio personal, shell /bin/bash y contraseña.

  2. Renombra el usuario seguridad a analista.

  3. Cambia su directorio personal a /home/analista moviendo su contenido.

  4. Ejecuta id analista. ¿Cómo se llama su grupo principal? Corrige la inconsistencia.

  5. Verifica los cambios en /etc/passwd y comprueba el propietario, el grupo y los permisos de /home/analista.

  6. Cambia la shell de analista a /bin/sh con chsh y después restáurala a /bin/bash. ¿Qué requisito debe cumplir la shell elegida?


8.6. Ejercicio 6. Caducidad de contraseñas y cuentas temporales

Las cuentas temporales (becarios, auditores externos, contratistas) deben caducar automáticamente para que no queden habilitadas cuando ya no se necesitan.

Realice los siguientes pasos:

  1. Aplica al usuario analista una caducidad de contraseña de 45 días con aviso 5 días antes, y verifica la configuración.

  2. Crea el usuario temporal becario de forma que su cuenta expire dentro de 90 días y se desactive 15 días después de que caduque su contraseña.

  3. Asígnale una contraseña, fuerza el cambio en el primer inicio de sesión y verifica todos sus parámetros.

  4. Localiza los campos correspondientes en la línea de becario de /etc/shadow y relaciona cada uno con la salida de chage -l.

  5. Reflexiona: según NIST SP 800-63B, ¿tiene sentido obligar a cambiar la contraseña cada 45 días? ¿Y fijar una fecha de expiración para la cuenta del becario?


8.7. Ejercicio 7. Bloqueo parcial frente a bloqueo completo

Un error habitual es pensar que passwd -l impide por completo el acceso a una cuenta. En este ejercicio comprobará la diferencia entre deshabilitar la contraseña y bloquear la cuenta.

Realice los siguientes pasos:

  1. Bloquea la contraseña de analista con passwd -l y comprueba su estado con passwd -S.

  2. Desde tu usuario, intenta iniciar sesión como analista con su -. ¿Qué ocurre?

  3. Explica por qué este bloqueo no impide el acceso por SSH con clave pública en la configuración por defecto de Debian/Ubuntu.

    Ampliación con SSH: esta prueba requiere un servidor SSH en la máquina virtual y funciona con cualquier máquina, tanto si admite contraseñas como si solo permite claves públicas. Como ssh-copy-id exige poder autenticarse antes con contraseña, no se utiliza. Antes del paso 1, instale el servidor si no está presente, genere un par de claves de uso exclusivo para la práctica, instale la clave pública en la cuenta analista y compruebe que ssh analista@localhost funciona. Repita la conexión tras passwd -l y de nuevo tras el bloqueo completo del paso 4.

  4. Aplica ahora un bloqueo completo haciendo que la cuenta haya expirado, y comprueba el resultado con chage -l.

  5. Intenta de nuevo su - analista (y, si hiciste la ampliación, la conexión SSH con la clave de la práctica). ¿Qué mensaje aparece ahora? Compáralo con el que aparece al ejecutar sudo su - analista -c id, y explica por qué su - analista sin sudo no llega a mostrar el aviso de cuenta caducada.

  6. Desbloquea completamente la cuenta.


8.8. Ejercicio 8. Baja segura y reutilización de UID

Eliminar usuarios es parte del mantenimiento seguro del sistema, pero hacerlo sin precauciones puede dejar archivos huérfanos que acaban en manos de otro usuario.

Realice los siguientes pasos:

  1. Crea el usuario usuario3, anota su UID y crea como usuario3 un archivo fuera de su directorio personal.

  2. Bloquea por completo la cuenta antes de eliminarla.

  3. Comprueba que no tiene procesos en ejecución ni tareas programadas.

  4. Localiza todos los archivos del usuario en el sistema y haz una copia de seguridad de su directorio personal en /backup.

  5. Elimina la cuenta y su directorio personal, y comprueba que ya no existe.

  6. Busca archivos huérfanos (sin usuario o sin grupo válido).

  7. Crea un nuevo usuario usuario4, consulta su UID y vuelve a listar /tmp/secreto_usuario3.txt. ¿Qué ha ocurrido? ¿Qué riesgo supone?

  8. Elimina el archivo /tmp/secreto_usuario3.txt.


8.9. Ejercicio 9. Grupos, gpasswd y directorio compartido

En entornos reales se crean grupos para organizar usuarios por departamentos o funciones, y se delega su gestión en los responsables de cada equipo.

Realice los siguientes pasos:

  1. Crea los grupos soporte, redes y tecnicos.

  2. Crea usuario1 (miembro de soporte y tecnicos) y usuario2 (miembro de redes y tecnicos) en un solo comando cada uno.

  3. Nombra a usuario1 administrador del grupo tecnicos y comprueba el cambio en /etc/gshadow.

  4. Actuando como usuario1 (y sin usar sudo para el comando gpasswd), añade a analista al grupo tecnicos.

  5. Crea el directorio compartido /srv/tecnicos, accesible solo para root y los miembros del grupo tecnicos.

  6. Comprueba que usuario1 puede crear un archivo en /srv/tecnicos y que auditor no puede.

  7. Renombra el grupo redes a comunicaciones y verifica que usuario2 sigue perteneciendo a él.

  8. Intenta eliminar el grupo analista. ¿Por qué falla?


8.10. Ejercicio 10. Detección de una puerta trasera con UID 0

Una técnica habitual de persistencia tras comprometer un sistema consiste en crear una cuenta con un nombre aparentemente inofensivo (admin, support, toor…) y UID 0. En este ejercicio simulará el ataque y lo detectará como lo haría un auditor.

Realice los siguientes pasos:

  1. (Simulación del atacante) Crea la cuenta toor con UID 0 y GID 0, usando /root como directorio personal y sin crearlo.

  2. (Auditoría) Lista todas las cuentas con UID 0.

  3. Detecta los UID duplicados del sistema.

  4. Comprueba qué nombre de usuario muestra el sistema para los archivos de root y para tus procesos con sudo. ¿Por qué podría pasar desapercibida la cuenta?

  5. Elimina la cuenta toor sin borrar el directorio /root. Comprueba antes si tiene sesiones abiertas, bloquea la cuenta y elimínala con userdel -f. Observa qué ocurre si omites la opción -f.

    No utilice nunca userdel -r en este caso: borraría el directorio /root. Tampoco intente detener sus procesos con pkill -u toor: como comparte el UID 0, la orden señalizaría todos los procesos de root. Sin la opción -f, userdel falla porque todos los procesos de root cuentan como del usuario toor.


8.11. Ejercicio 11. Auditoría de grupos privilegiados y sudo

Antes de aplicar medidas de bastionado, el administrador debe saber quién puede convertirse en root, ya sea a través de sudo o de grupos privilegiados.

Realice los siguientes pasos:

  1. Lista los miembros de los grupos privilegiados sudo, adm, docker, lxd, disk y shadow (algunos pueden no existir en tu sistema).

  2. Muestra las reglas activas de /etc/sudoers y de /etc/sudoers.d/, sin comentarios ni líneas vacías.

  3. Consulta qué privilegios sudo tienen tu usuario y analista.

  4. Añade a analista al grupo sudo, comprueba de nuevo sus privilegios y, a continuación, revócalos.

  5. Crea con visudo el archivo /etc/sudoers.d/soporte para que los miembros del grupo soporte solo puedan ejecutar systemctl status ssh como root. Valida la sintaxis.

  6. Comprueba los privilegios resultantes de usuario1 y de usuario2.

  7. Busca en GTFOBins qué ocurriría si la regla anterior permitiera ejecutar /usr/bin/less o /usr/bin/find en lugar de systemctl status ssh.


8.12. Ejercicio 12. Controles CIS y script de auditoría

Las herramientas de verificación del sistema y los controles del CIS Benchmark permiten detectar corrupciones de archivos, identificadores duplicados, cuentas sin contraseña y membresías peligrosas. En este ejercicio los aplicará manualmente y después los automatizará.

Realice los siguientes pasos:

  1. Ejecuta pwck y grpck en modo solo lectura e interpreta los avisos.

  2. Comprueba los permisos de los archivos de cuentas y de sus copias de respaldo.

  3. Verifica que el grupo shadow no tiene miembros y que no existen UID, GID ni nombres duplicados.

  4. (Simulación) Elimina la contraseña de prueba1 con passwd -d, detecta la cuenta sin contraseña con awk y corrige el problema bloqueándola.

  5. Configura el cierre de sesión por inactividad (TMOUT=900, de solo lectura) en /etc/profile.d/timeout.sh. Abre una nueva sesión de login y comprueba que no se puede desactivar con unset TMOUT.

  6. Escribe un script auditoria_cuentas.sh que ejecute los siguientes controles y muestre OK o ALERTA para cada uno:

    • Solo existe una cuenta con UID 0.

    • No hay cuentas sin contraseña.

    • No hay UID, GID ni nombres duplicados.

    • El grupo shadow no tiene miembros.

    • Ninguna cuenta de sistema (UID 1-999) tiene shell interactiva.

    • /etc/shadow y /etc/gshadow tienen permisos 640 o más restrictivos.

    • Ningún directorio de /home es accesible por “otros”.

    • Lista de miembros de los grupos privilegiados.


8.13. Ejercicio 13. Limpieza del entorno

Para terminar, revierta los cambios realizados durante la práctica.

Realice los siguientes pasos:

  1. Elimina los usuarios creados durante la práctica junto con sus directorios personales: prueba1, appsvc, analista, becario, auditor, usuario1, usuario2 y usuario4. Si realizó la ampliación con SSH del ejercicio 7, cierre antes las sesiones de analista, que pueden permanecer activas unos segundos, y elimine el par de claves de la práctica.

  2. Elimina los grupos soporte, comunicaciones y tecnicos, el directorio /srv/tecnicos, la regla /etc/sudoers.d/soporte y el directorio /backup con la copia de usuario3.

  3. Restaura /etc/login.defs y /etc/skel/.profile a partir de las copias de seguridad, y el valor por defecto de INACTIVE de useradd.

  4. Comprueba con pwck, grpck y tu script de auditoría que el sistema queda en un estado coherente, y elimina el rango subordinado que quedó huérfano al renombrar seguridad en el ejercicio 5 (ver apartado 6.2.2). Decide si quieres conservar /etc/profile.d/timeout.sh.

Con la realización de estos ejercicios prácticos se consolidan los procedimientos esenciales de auditoría, administración segura y bastionado de cuentas y grupos locales en sistemas Linux, asegurando la integridad de los archivos de autenticación y el cumplimiento de las directrices del CIS Benchmark.

9. Licencia

Licencia CC BY-NC-ND 4.0

Esta página forma parte del curso Bastionado de Redes y Sistemas © 2026 de José Juan Sánchez Hernández y su contenido se distribuye bajo una licencia Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International.

Esta licencia exige que quienes reutilicen el material otorguen el debido crédito al autor. Permite copiar y redistribuir el material en cualquier medio o formato, únicamente en su forma original, y solo para fines no comerciales.