Movimiento lateral en Linux: diferente ecosistema, mismos principios
Cuando pensamos en movimiento lateral, la conversación suele centrarse en entornos Windows: EVTX, Kerberos, PsExec, RDP. Pero los entornos empresariales modernos son híbridos, y los atacantes no se detienen en las fronteras del sistema operativo. Servidores Linux, especialmente los que ejecutan servicios web, bases de datos o infraestructura de contenedores, son objetivos frecuentes.
El vector principal de movimiento lateral en Linux es SSH. A diferencia de Windows, donde existen múltiples protocolos de acceso remoto (RDP, WMI, WinRM, SMB), en Linux prácticamente todo el acceso remoto pasa por SSH, lo que simplifica el análisis pero también exige conocer exactamente dónde buscar.
Masstin soporta el parseo de logs de Linux, integrando la actividad SSH en la misma timeline de movimiento lateral que los artefactos de Windows.
/var/log/secure y /var/log/auth.log
Dependiendo de la distribución, los eventos de autenticación se registran en:
- /var/log/secure — Red Hat, CentOS, Fedora, Rocky Linux
- /var/log/auth.log — Debian, Ubuntu
Ambos contienen la misma información, solo cambia la ruta.
Logon SSH exitoso
Un logon SSH exitoso genera una línea como esta:
Apr 7 14:23:01 servidor sshd[12345]: Accepted publickey for admin from 10.0.1.50 port 52341 ssh2
| Campo | Descripción |
|---|---|
| Timestamp | Fecha y hora del evento |
| Hostname | Máquina donde se produjo el logon |
| PID | Process ID del proceso sshd que gestiona la sesión |
| Método | publickey, password, keyboard-interactive, gssapi-with-mic (Kerberos) |
| Usuario | Cuenta que inició sesión |
| IP origen | Dirección IP desde la que se conectó |
| Puerto origen | Puerto efímero del cliente |
Indicadores de movimiento lateral:
- Logon con
passworddesde una IP interna que normalmente usa clave pública.- Logon como
rootdirectamente (siPermitRootLoginestá habilitado).- Logon desde una IP no reconocida o fuera de horario laboral.
Logon SSH fallido
Apr 7 14:23:05 servidor sshd[12346]: Failed password for admin from 10.0.1.50 port 52342 ssh2
Apr 7 14:23:06 servidor sshd[12346]: Failed password for invalid user test from 10.0.1.50 port 52343 ssh2
| Patrón | Significado |
|---|---|
Failed password for <usuario> |
Contraseña incorrecta para usuario existente |
Failed password for invalid user <usuario> |
El usuario no existe en el sistema |
Connection closed by <IP> [preauth] |
Conexión cerrada antes de completar autenticación |
Too many authentication failures |
Múltiples intentos fallidos — fuerza bruta |
Detección de fuerza bruta: Una ráfaga de
Failed passwordseguida de unAccepted passwordindica fuerza bruta exitosa.
Eventos de conexión y desconexión
Apr 7 14:23:01 servidor sshd[12345]: Connection from 10.0.1.50 port 52341
Apr 7 14:45:30 servidor sshd[12345]: Disconnected from user admin 10.0.1.50 port 52341
Apr 7 14:45:30 servidor sshd[12345]: pam_unix(sshd:session): session closed for user admin
Estos eventos permiten calcular la duración de la sesión y confirmar que la sesión se cerró de forma limpia.
/var/log/messages
En distribuciones basadas en Red Hat, /var/log/messages registra eventos del sistema general, incluyendo algunos relacionados con SSH y PAM que no aparecen en /var/log/secure.
| Tipo de entrada | Ejemplo | Relevancia |
|---|---|---|
| PAM session opened | pam_unix(sshd:session): session opened for user admin |
Confirma inicio de sesión SSH |
| PAM session closed | pam_unix(sshd:session): session closed for user admin |
Confirma cierre de sesión |
| systemd-logind | New session 42 of user admin |
Sesión registrada por systemd |
| su/sudo | admin : TTY=pts/0 ; COMMAND=/bin/bash |
Escalada de privilegios post-logon |
/var/log/audit/audit.log
El subsistema de auditoría de Linux (auditd) proporciona un nivel de detalle superior al de los logs estándar. Es especialmente útil cuando se configuran reglas específicas para monitorizar SSH y accesos remotos.
Eventos SSH en audit.log
type=USER_AUTH msg=audit(1712502181.123:4567): pid=12345 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:authentication grantors=pam_unix acct="admin" exe="/usr/sbin/sshd" hostname=10.0.1.50 addr=10.0.1.50 terminal=ssh res=success'
| Campo | Descripción |
|---|---|
| type | USER_AUTH (autenticación), USER_LOGIN (logon), USER_LOGOUT (logout) |
| pid | PID del proceso sshd |
| acct | Cuenta autenticada |
| exe | Ejecutable que realizó la autenticación |
| hostname / addr | IP de origen |
| res | success o failed |
Tipos de registro relevantes para movimiento lateral:
| Tipo audit | Descripción |
|---|---|
| USER_AUTH | Resultado de autenticación PAM |
| USER_LOGIN | Logon de usuario completado |
| USER_LOGOUT | Logout de usuario |
| CRED_ACQ | Credenciales adquiridas |
| CRED_DISP | Credenciales liberadas |
| USER_ACCT | Verificación de cuenta (existe, no expirada, etc.) |
Ventaja de audit.log: A diferencia de
/var/log/secure, audit.log usa un formato estructurado con timestamps Unix precisos, lo que facilita la correlación temporal con otros artefactos.
utmp, wtmp y btmp
Estos son archivos binarios que registran información de sesiones de usuario. No se pueden leer con cat — requieren herramientas como who, w, last, lastb y utmpdump.
utmp — Sesiones activas
Ubicación: /var/run/utmp
Registra las sesiones actualmente abiertas en el sistema. Es lo que consultan los comandos who y w.
| Campo | Descripción |
|---|---|
| ut_type | Tipo de registro (USER_PROCESS, LOGIN_PROCESS, etc.) |
| ut_user | Nombre de usuario |
| ut_line | Terminal (ej: pts/0, tty1) |
| ut_host | IP o hostname de origen (para sesiones remotas) |
| ut_time | Timestamp del evento |
Limitación: utmp solo contiene sesiones activas. Cuando una sesión se cierra, se elimina de utmp y se escribe en wtmp.
wtmp — Historial de sesiones
Ubicación: /var/log/wtmp
Registra todas las sesiones de logon y logout, incluyendo reinicios del sistema. Es un registro histórico acumulativo.
last -f /var/log/wtmp
Salida típica:
admin pts/0 10.0.1.50 Mon Apr 7 14:23 - 14:45 (00:22)
root pts/1 10.0.1.100 Mon Apr 7 03:15 - 03:17 (00:02)
reboot system boot 5.14.0-284.el9 Mon Apr 7 00:00
| Información | Relevancia forense |
|---|---|
| Usuario + IP origen | Quién se conectó y desde dónde |
| Terminal | pts/* = sesión remota (SSH/telnet), tty* = consola local |
| Duración | Tiempo de la sesión — sesiones cortas pueden ser automatizadas |
| Reinicios | El evento reboot indica arranques del sistema |
Análisis forense: Sesiones de
rootdesde IPs internas a las 3 AM con duración de 2 minutos son altamente sospechosas.
btmp — Intentos de logon fallidos
Ubicación: /var/log/btmp
Registra todos los intentos de logon fallidos. Es el equivalente Linux del Event ID 4625 de Windows.
lastb -f /var/log/btmp
Salida típica:
admin ssh:notty 10.0.1.50 Mon Apr 7 14:22 - 14:22 (00:00)
root ssh:notty 192.168.1.200 Mon Apr 7 14:22 - 14:22 (00:00)
test ssh:notty 10.0.1.50 Mon Apr 7 14:22 - 14:22 (00:00)
Detección de ataques:
- Múltiples entradas desde la misma IP con diferentes usuarios = password spraying.
- Múltiples entradas con el mismo usuario desde la misma IP = fuerza bruta.
- Intentos con usuarios como
admin,test,root,oracle= ataque de diccionario.
lastlog — Último logon por usuario
Ubicación: /var/log/lastlog
Registra la fecha, hora y origen del último logon exitoso de cada usuario del sistema.
lastlog
Salida típica:
Username Port From Latest
root pts/1 10.0.1.100 Mon Apr 7 03:15:22 +0100 2026
admin pts/0 10.0.1.50 Mon Apr 7 14:23:01 +0100 2026
www-data **Never logged in**
Valor forense: Si una cuenta de servicio como
www-dataopostgresmuestra un logon reciente, es un fuerte indicador de compromiso — estas cuentas normalmente no tienen logons interactivos.
Logs binarios de systemd-journald — la mitad que falta en el Linux moderno
En Ubuntu 18+, Debian 11+, RHEL 8+ y en cualquier distribución donde SSSD esté enrolado en Active Directory, /var/log/auth.log suele estar casi vacío. No es un problema de retención ni de rotación, es por diseño: systemd-journald captura la corriente de eventos y o bien rsyslog/syslog-ng no reenvía los eventos SSH al fichero de texto, o simplemente no está instalado. El registro real de SSH vive en el journal binario bajo:
/var/log/journal/<machine-id>/system.journal
/var/log/journal/<machine-id>/system@<secuencia>.journal
/var/log/journal/<machine-id>/system@<secuencia>.journal~ # archivado (rotado)
Cada fichero .journal es una base de datos binaria:
- Cabecera + arena de
OBJECT_DATA(campos tipoMESSAGE=,_COMM=sshd,_HOSTNAME=,_UID=0) yOBJECT_ENTRY(una entrada de log que referencia un conjunto de data objects). - Modo compacto (versiones recientes de
journalctl) usa offsets de 4 bytes en lugar de 8 bytes + hash, para ocupar menos. - Payloads comprimidos con zstd para campos
MESSAGEgrandes (es el default en Ubuntu 22+).
Los campos que importan para análisis forense de movimiento lateral:
| Campo | Qué contiene |
|---|---|
_COMM |
Nombre del comando — sshd, sudo, systemd, etc. Filtrar por sshd corta el ruido rápido. |
SYSLOG_IDENTIFIER |
Identificador estilo syslog, normalmente igual a _COMM para servicios simples. |
MESSAGE |
La línea de log real — p.ej. Accepted publickey for ubuntu from 192.168.10.1 port 41764 ssh2 |
_HOSTNAME |
Host que emitió el evento. Útil cuando has agregado journals de varias máquinas. |
_PID |
PID del sshd de la sesión. |
__REALTIME_TIMESTAMP |
Microsegundos desde epoch Unix — siempre presente, siempre preciso. |
Lo bonito es que la línea de log dentro de MESSAGE es textualmente idéntica a la que verías en auth.log en una configuración clásica de syslog:
Accepted publickey for ubuntu from 192.168.10.1 port 41764 ssh2: RSA SHA256:/uCIzrTZ...
Failed password for invalid user test from 203.0.113.9 port 43112 ssh2
Por tanto, las mismas regex que matchean /var/log/auth.log también matchean el MESSAGE de los ficheros .journal — solo hace falta un lector que sepa recorrer el formato binario y entregarte la cadena MESSAGE.
Por qué esto importa en Linux enrolado en dominio
En un servidor Ubuntu unido a un dominio Active Directory vía SSSD (realmd join, adcli…), la imagen típica que ve el analista es esta:
$ cat /var/log/auth.log | grep sshd
(vacío — o como mucho unos pocos mensajes de systemd-logind sobre seats)
$ sudo journalctl -u ssh --since "-30d" | grep Accepted
Apr 12 18:20:44 LNX01-oldtown sshd[2134]: Accepted publickey for ubuntu from 192.168.10.1 port 41764 ssh2
Apr 12 18:20:53 LNX01-oldtown sshd[2141]: Accepted publickey for ubuntu from 192.168.10.1 port 57200 ssh2
...
Si extraes /var/log/auth.log de una imagen forense ext4 y lo parseas con una herramienta clásica, concluirás “aquí no pasó nada” — y te perderás el 100% de la evidencia de movimiento lateral. Cualquier pipeline de DFIR que ignore el journal binario en Linux moderno tiene un punto ciego del tamaño de toda la huella SSH.
Masstin gestiona esto de forma nativa: lee directamente los ficheros .journal y .journal~, decodifica el modo compacto y los data objects comprimidos con zstd, filtra por _COMM=sshd y aplica las mismas regex Accepted (password|publickey) / Failed password que usa sobre logs de texto. La implementación es Rust puro — sin binding a libsystemd — con lo cual también funciona cuando analizas evidencia Linux desde una workstation DFIR con Windows.
Tabla resumen de artefactos Linux
| Artefacto | Ubicación | Formato | Qué registra | Herramienta de lectura |
|---|---|---|---|---|
| auth.log / secure | /var/log/auth.log (Debian/Ubuntu) o /var/log/secure (RHEL) |
Texto | Autenticación SSH (éxitos, fallos, conexiones) — a menudo vacío en hosts SSSD + AD | cat, grep |
| messages | /var/log/messages |
Texto | Eventos del sistema, PAM, systemd | cat, grep |
| audit.log | /var/log/audit/audit.log |
Texto estructurado | USER_LOGIN / USER_AUTH / USER_START — auditoría detallada, señal SSH primaria en Ubuntu + SSSD |
ausearch, aureport |
| systemd-journald | /var/log/journal/<machine-id>/*.journal[~] |
Binario (comprimido con zstd) | Todos los eventos sshd en distros modernas (Ubuntu 18+, RHEL 8+, Debian 11+) — el registro real de SSH cuando auth.log está vacío |
journalctl --file, masstin |
| utmp | /var/run/utmp |
Binario | Sesiones activas | who, w |
| wtmp | /var/log/wtmp |
Binario | Historial de logon/logout | last |
| btmp | /var/log/btmp |
Binario | Logons fallidos | lastb |
| lastlog | /var/log/lastlog |
Binario | Último logon por usuario | lastlog |
Cómo masstin parsea artefactos Linux
Masstin soporta el parseo de logs de autenticación Linux — ficheros de texto (/var/log/auth.log, /var/log/secure, /var/log/audit/audit.log), accounting binario (utmp/wtmp/btmp/lastlog) y los logs binarios de systemd-journald bajo /var/log/journal/ — y normaliza cada evento al mismo formato CSV que utiliza para los artefactos Windows.
# Directorio con logs extraidos
masstin -a parse-linux -d /evidence/var/log/ -o timeline.csv
# Paquete forense comprimido (extraccion automatica, soporta contrasenas)
masstin -a parse-linux -d /evidence/triage_package/ -o timeline.csv

Masstin reporta de forma transparente todas las inferencias: identificación del hostname (desde /etc/hostname, dmesg o la cabecera syslog), inferencia del año (desde dpkg.log, wtmp o fecha de modificación del fichero) y extracción de ZIPs protegidos con contraseña.
Esto permite crear timelines de movimiento lateral que cruzan las fronteras de sistema operativo: un atacante que se mueve de una workstation Windows a un servidor Linux vía SSH aparecerá en la misma timeline que sus movimientos RDP o SMB.
Compatibilidad entre distribuciones
Los logs de Linux difieren según la distribución, pero masstin los maneja de forma transparente:
| Distribución | Fuente principal | Formato |
|---|---|---|
| Debian, Ubuntu (rsyslog clásico) | /var/log/auth.log |
RFC3164 (syslog legacy) |
| RHEL, CentOS, Fedora, Rocky | /var/log/secure |
RFC3164 (syslog legacy) |
| Cualquiera (rsyslog estructurado) | Variable | RFC5424 |
| Ubuntu 18+ / Debian 11+ / RHEL 8+ (stock, sin rsyslog) | /var/log/journal/<id>/*.journal[~] |
Binario (comprimido con zstd) — parseado directamente |
| SSSD + Active Directory (Ubuntu 22, RHEL 9) | /var/log/journal/ + /var/log/audit/audit.log |
Binario + texto estructurado |
Formatos de timestamp
RFC3164 (el más común en la práctica) usa timestamps sin año:
Mar 16 08:25:22 app-1 sshd[4894]: Accepted password for user3 from 192.168.126.1 port 61474 ssh2
Dado que RFC3164 no incluye el año, masstin lo infiere automáticamente de ficheros vecinos en el mismo directorio. El orden de prioridad es: dpkg.log (contiene fechas completas YYYY-MM-DD), wtmp (timestamps epoch con año), fecha de modificación del fichero, y año actual como último recurso. Masstin reporta qué infiere y de qué fuente lo obtiene, para que el analista siempre conozca la base de los timestamps.
Lo mismo aplica a la identificación del hostname: masstin comprueba /etc/hostname, dmesg, /etc/hosts, y como fallback extrae el hostname de la propia cabecera syslog. Todas las inferencias se reportan de forma transparente en la salida.
RFC5424 (syslog estructurado) incluye timestamps completos con zona horaria:
<38>1 2024-03-16T08:25:22+00:00 app-1 sshd 4894 - - Accepted password for user3 from 192.168.126.1 port 61474 ssh2
Este formato se utiliza cuando se exporta el journal de systemd o cuando rsyslog está configurado con salida estructurada.
Soporte de triage comprimido
Al igual que parse-windows, parse-linux puede procesar paquetes de triage comprimidos directamente. Descomprime archivos ZIP de forma recursiva — incluyendo archivos protegidos con contraseña utilizando contraseñas forenses comunes (cyberdefenders.org, infected, malware, password). Cuando se detecta y desbloquea un archivo protegido, masstin notifica al usuario.
Conclusión
En entornos híbridos, ignorar los artefactos Linux deja puntos ciegos críticos en la investigación. Los logs de autenticación SSH, los registros binarios utmp/wtmp/btmp y audit.log proporcionan la misma riqueza forense que los EVTX de Windows — solo hay que saber dónde buscar.
Masstin unifica estos artefactos con los de Windows para darte una visión completa del movimiento lateral a través de toda la infraestructura.
$ comments