Threat Hunting: Movimiento Lateral con Sysmon y SIEM
Guía práctica de threat hunting para detectar movimiento lateral en redes corporativas. Hypothesis-driven hunting con Sysmon events, detección de PsExec, WMI lateral, RDP anomalías y Pass-the-Hash. Queries para Splunk y Elastic.
Por qué cazar movimiento lateral
El movimiento lateral es la fase que transforma un compromiso puntual en un incidente a escala de toda la organización. Un atacante con acceso a una estación de trabajo es un problema. Un atacante moviéndose libremente entre servidores y controladores de dominio es una crisis.
Los EDR modernos detectan muchas técnicas conocidas, pero los atacantes sofisticados usan herramientas legítimas del sistema (Living off the Land) y técnicas que generan eventos indistinguibles del tráfico administrativo normal. El threat hunting llena ese vacío: parte de hipótesis sobre comportamientos sospechosos y busca evidencia en los datos de telemetría.
Este artículo documenta un hunt completo enfocado en movimiento lateral. Incluye las hipótesis, los eventos Sysmon relevantes, queries para Splunk y Elastic, el análisis de resultados y las reglas de detección que se derivaron.
Prerequisitos: configuración de Sysmon
Antes de cazar, necesitas visibilidad. Sysmon debe estar instalado y configurado para capturar los eventos que vamos a analizar. La configuración recomendada (basada en SwiftOnSecurity/sysmon-config con modificaciones) debe incluir al mínimo estos Event IDs:
| Event ID | Nombre | Relevancia para movimiento lateral |
|---|---|---|
| 1 | Process Create | Detectar ejecución de herramientas remotas (PsExec, WMIC) |
| 3 | Network Connection | Conexiones SMB (445), RDP (3389), WinRM (5985/5986) |
| 5 | Process Terminated | Correlacionar duración de procesos sospechosos |
| 7 | Image Loaded | DLLs cargadas por procesos inyectados |
| 8 | CreateRemoteThread | Inyección en procesos remotos (Cobalt Strike, Meterpreter) |
| 10 | Process Access | Acceso a LSASS para credential dumping |
| 11 | File Create | Archivos creados remotamente (payloads, herramientas) |
| 13 | Registry Value Set | Persistencia via registro |
| 17 | Pipe Created | Named pipes de herramientas de lateral movement |
| 18 | Pipe Connected | Conexión a pipes existentes |
Fragmento de configuración Sysmon
<!-- Sysmon config excerpt for lateral movement hunting -->
<EventFiltering>
<!-- Event ID 3: Network Connection -->
<NetworkConnect onmatch="include">
<DestinationPort condition="is">445</DestinationPort>
<DestinationPort condition="is">3389</DestinationPort>
<DestinationPort condition="is">5985</DestinationPort>
<DestinationPort condition="is">5986</DestinationPort>
<DestinationPort condition="is">135</DestinationPort>
</NetworkConnect>
<!-- Event ID 10: Process Access to LSASS -->
<ProcessAccess onmatch="include">
<TargetImage condition="is">C:\Windows\System32\lsass.exe</TargetImage>
</ProcessAccess>
<!-- Event ID 17/18: Named Pipes -->
<PipeEvent onmatch="exclude">
<PipeName condition="begin with">\lsass</PipeName>
<PipeName condition="begin with">\wkssvc</PipeName>
<!-- Exclude known legitimate pipes to reduce noise -->
</PipeEvent>
</EventFiltering>
Hipótesis 1: Movimiento lateral con PsExec
Formulación de la hipótesis
Hipótesis: Un atacante que ha comprometido credenciales de administrador está usando PsExec (o variantes) para ejecutar comandos remotamente en otros equipos de la red.
Fundamento: PsExec es la herramienta de movimiento lateral más documentada (T1021.002, T1570). Aunque es una herramienta legítima de Sysinternals, su uso fuera del equipo de IT es altamente sospechoso. Las variantes maliciosas (PsExec de Cobalt Strike, Impacket's smbexec) generan artefactos similares.
Datos necesarios: Sysmon Event ID 1, 17, 18 y Security Event Log 4624.
Indicadores de PsExec
PsExec genera un patrón reconocible:
- Se copia
PSEXESVC.exeal equipo remoto via SMB (\\target\ADMIN$) - Se crea un servicio con nombre aleatorio o
PSEXESVC - Se crea un named pipe para comunicación (
\PSEXESVC-*) - El comando se ejecuta como hijo de
PSEXESVC.exe
Query Splunk
index=sysmon EventCode=17
| where match(PipeName, "(?i)\\\\psexe|\\\\MSSE-|\\\\msagent_|\\\\status_|\\\\postex_")
| stats count by Computer, Image, PipeName, User
| where count > 0
| sort -count
index=sysmon EventCode=1
ParentImage="*\\PSEXESVC.exe" OR ParentImage="*\\services.exe"
| where Image!="C:\\Windows\\System32\\svchost.exe"
| stats count values(CommandLine) as commands by Computer, ParentImage, Image, User
| sort -count
Query Elastic (KQL)
event.code: "17" AND winlog.event_data.PipeName: (*psexe* OR *MSSE-* OR *msagent_* OR *postex_*)
event.code: "1" AND process.parent.executable: (*PSEXESVC* OR *services.exe)
AND NOT process.executable: *svchost.exe
Análisis de resultados
En un entorno de 500 endpoints, el hunt devuelve:
- 12 eventos legítimos: el equipo de IT usa PsExec para tareas de mantenimiento desde 2 estaciones de trabajo conocidas (IT-WS01, IT-WS02), ejecutando scripts de inventario
- 0 eventos sospechosos: no se detecta PsExec desde estaciones no autorizadas
Acción: crear una allowlist de estaciones de IT autorizadas para PsExec y una regla de alerta para cualquier uso de PsExec desde estaciones fuera de esa lista.
Regla de detección derivada (Sigma)
title: PsExec Execution from Non-IT Workstation
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: production
description: Detects PsExec or similar remote execution tools from workstations not in the IT allowlist
logsource:
product: windows
service: sysmon
category: pipe_created
detection:
selection:
EventID: 17
PipeName|contains:
- '\psexe'
- '\MSSE-'
- '\msagent_'
filter:
Computer:
- 'IT-WS01'
- 'IT-WS02'
condition: selection and not filter
level: high
tags:
- attack.lateral_movement
- attack.t1021.002
Hipótesis 2: WMI como vector de lateral movement
Formulación de la hipótesis
Hipótesis: Un atacante está usando Windows Management Instrumentation (WMI) para ejecutar comandos o crear procesos en equipos remotos (T1047).
Fundamento: WMI es una técnica Living off the Land que no requiere copiar herramientas al equipo remoto. El comando wmic /node:TARGET process call create ejecuta procesos sin dejar archivos en disco. Es más sigilosa que PsExec porque no crea servicios ni named pipes.
Indicadores de WMI lateral
La ejecución remota via WMI genera:
- En el equipo origen: proceso
wmic.execon parámetro/node:en la línea de comandos - En el equipo destino: proceso
wmiprvse.exe(WMI Provider Host) como padre del comando ejecutado - Conexión de red al puerto 135 (RPC) seguida de puertos efímeros
Query Splunk
index=sysmon EventCode=1
(Image="*\\wmic.exe" CommandLine="*/node:*")
OR (ParentImage="*\\WmiPrvSE.exe"
Image!="*\\WmiPrvSE.exe"
Image!="*\\WmiApSrv.exe"
Image!="*\\svchost.exe"
Image!="*\\scrcons.exe")
| eval direction=if(match(Image,"wmic.exe"),"OUTBOUND","INBOUND")
| stats count values(CommandLine) as cmds values(direction) as dir by Computer, User, Image
| sort -count
Query Elastic (KQL)
(event.code: "1" AND process.executable: *wmic.exe AND process.command_line: */node*)
OR (event.code: "1" AND process.parent.executable: *WmiPrvSE.exe
AND NOT process.executable: (*WmiPrvSE* OR *svchost* OR *WmiApSrv*))
Análisis de resultados
El hunt encuentra:
- 47 eventos de SCCM: el servidor de SCCM usa WMI legítimamente para inventario y distribución de software. Siempre desde
SCCM-SRV01con usuariosvc_sccm. - 3 eventos sospechosos:
wmiprvse.exeen el servidorAPP-SRV03ejecutandopowershell.exe -enccomo hijo. El usuario esadmin_jgarciadesdeWS-FINANCE02.
Investigación adicional del hallazgo sospechoso:
index=sysmon (Computer="APP-SRV03" OR Computer="WS-FINANCE02")
User="admin_jgarcia"
| sort _time
| table _time Computer EventCode Image CommandLine DestinationIp DestinationPort
Resultado: admin_jgarcia es un administrador legítimo que usó WMI para reiniciar un servicio en APP-SRV03 durante una ventana de mantenimiento. El PowerShell codificado era un script de reinicio de servicio IIS.
Acción: documentar el uso legítimo, crear regla de alerta para WMI remoto fuera de ventanas de mantenimiento y con PowerShell codificado.
Hipótesis 3: Anomalías en RDP
Formulación de la hipótesis
Hipótesis: Un atacante está usando RDP (T1021.001) para moverse lateralmente, posiblemente con credenciales robadas o reenviando sesiones existentes.
Fundamento: RDP es el protocolo de acceso remoto más usado en entornos Windows corporativos. Los atacantes lo prefieren porque proporciona interfaz gráfica completa y el tráfico se mezcla con el uso legítimo. Las anomalías en horarios, orígenes o cuentas pueden revelar uso malicioso.
Indicadores de RDP anómalo
Los indicadores a buscar no son eventos individuales sino patrones:
- Conexiones RDP desde estaciones de trabajo a servidores (lo normal es desde jump servers)
- RDP fuera de horario laboral desde cuentas no administrativas
- Múltiples conexiones RDP desde un mismo origen a diferentes destinos en poco tiempo (spray)
- RDP con credenciales de cuentas de servicio (nunca deberían usar RDP)
- Túneles RDP (RDP sobre SSH o sobre otros protocolos)
Query Splunk
index=sysmon EventCode=3 DestinationPort=3389
| where SourceIp!=DestinationIp
| bin _time span=1h
| stats dc(DestinationIp) as unique_destinations values(DestinationIp) as targets
by SourceIp, User, _time
| where unique_destinations > 3
| sort -unique_destinations
index=wineventlog EventCode=4624 LogonType=10
| eval hour=strftime(_time,"%H")
| where (hour >= 22 OR hour <= 5)
| stats count values(TargetUserName) as users values(IpAddress) as sources by Computer
| where count > 0
| sort -count
Query Elastic (KQL)
event.code: "3" AND destination.port: 3389 AND NOT source.ip: destination.ip
Para análisis temporal en Elastic, usar una agregación por histograma de hora:
{
"query": {
"bool": {
"must": [
{"term": {"event.code": "4624"}},
{"term": {"winlog.event_data.LogonType": "10"}}
]
}
},
"aggs": {
"by_hour": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "hour"
}
}
}
}
Análisis de resultados
El hunt identifica:
- Patrón normal: 95% de conexiones RDP provienen de los jump servers (
JUMP-01,JUMP-02) durante horario laboral (8:00 a 19:00) - Anomalía 1: 2 conexiones RDP a las 23:47 y 00:12 desde
WS-DEV05haciaDB-SRV01yDB-SRV02con la cuentaadmin_lperez - Anomalía 2: 7 conexiones RDP desde
WS-MARKETING03a 7 servidores diferentes en un período de 15 minutos (spray pattern)
Investigación de la Anomalía 2:
La cuenta usada es svc_monitor. Es una cuenta de servicio de monitorización que nunca debería abrir sesiones RDP interactivas. Esto es un indicador claro de compromiso de credenciales o uso indebido.
Resultado de la investigación: svc_monitor tenía una contraseña que no se había rotado en 18 meses. No se encontró evidencia de compromiso externo. La causa fue un técnico que usaba la cuenta de servicio para acceso rápido a servidores en lugar de su cuenta personal.
Acción: forzar rotación de password de svc_monitor, implementar Managed Service Accounts (gMSA) para eliminar contraseñas estáticas en cuentas de servicio, alertar sobre cualquier sesión RDP interactiva con cuentas svc_*.
Hipótesis 4: Pass-the-Hash
Formulación de la hipótesis
Hipótesis: Un atacante ha extraído hashes NTLM (T1003.001) y los está reutilizando para autenticarse en otros equipos sin conocer la contraseña en texto claro (T1550.002).
Fundamento: Pass-the-Hash (PtH) es una de las técnicas de movimiento lateral más efectivas porque no requiere crackear la contraseña. El hash NTLM funciona como credencial de autenticación en el protocolo NTLM. Si un atacante obtiene el hash de un administrador de dominio, puede autenticarse en cualquier equipo del dominio.
Indicadores de Pass-the-Hash
PtH genera un patrón específico en los logs de Windows:
- Event ID 4624 con LogonType 3 (Network logon) y AuthenticationPackage
NTLM(no Kerberos) - Event ID 4624 con LogonType 9 (NewCredentials) cuando se usa
sekurlsa::pthde Mimikatz - En el equipo origen: proceso no estándar creando conexiones SMB (no
explorer.exenisvchost.exe)
La dificultad es que la autenticación NTLM legítima genera los mismos Event IDs. La clave es correlacionar con el proceso origen.
Query Splunk
index=wineventlog EventCode=4624 LogonType=3
AuthenticationPackageName="NTLM"
TargetUserName!="ANONYMOUS LOGON"
TargetUserName!="*$"
| eval is_admin=if(match(TargetUserName,"(?i)admin|svc_|da_"),"yes","no")
| where is_admin="yes"
| stats count values(IpAddress) as source_ips dc(IpAddress) as unique_sources
by TargetUserName, Computer
| where unique_sources > 2
| sort -unique_sources
index=sysmon EventCode=10
TargetImage="*\\lsass.exe"
GrantedAccess IN ("0x1010", "0x1038", "0x143a", "0x1fffff")
| where NOT match(SourceImage, "(?i)csrss|services|lsass|svchost|MsMpEng|CrowdStrike")
| stats count values(GrantedAccess) as access by Computer, SourceImage, User
| sort -count
Query Elastic (KQL)
event.code: "4624" AND winlog.event_data.LogonType: "3"
AND winlog.event_data.AuthenticationPackageName: "NTLM"
AND NOT winlog.event_data.TargetUserName: ("ANONYMOUS LOGON" OR *$)
event.code: "10" AND winlog.event_data.TargetImage: *lsass.exe
AND winlog.event_data.GrantedAccess: ("0x1010" OR "0x1038" OR "0x143a" OR "0x1fffff")
AND NOT winlog.event_data.SourceImage: (*csrss* OR *services* OR *lsass* OR *MsMpEng*)
Análisis de resultados
El hunt de acceso a LSASS revela:
- Procesos legítimos filtrados: antivirus, EDR, servicios de Windows (ya excluidos en la query)
- 2 eventos sospechosos:
rundll32.exeaccediendo alsass.execon GrantedAccess0x1010enWS-HR04. El proceso padre esexplorer.exe.
Investigación profunda:
index=sysmon Computer="WS-HR04"
(EventCode=1 Image="*\\rundll32.exe")
OR (EventCode=10 SourceImage="*\\rundll32.exe")
| sort _time
| table _time EventCode Image CommandLine TargetImage GrantedAccess
Resultado: rundll32.exe fue invocado por un programa de captura de pantalla legítimo que accede a LSASS para verificar la sesión activa. Falso positivo documentado.
Acción: añadir el proceso del software de captura a la lista de exclusión, pero mantener la regla activa para otros procesos.
Hipótesis 5: Named Pipes anómalos (Cobalt Strike, Metasploit)
Formulación de la hipótesis
Hipótesis: un framework de C2 (Cobalt Strike, Metasploit, Sliver) está usando named pipes para comunicación entre procesos inyectados en la red (T1570, T1559.001).
Fundamento: Cobalt Strike usa named pipes como canal de comunicación para sus beacons SMB y para la funcionalidad de movimiento lateral. Los patrones de nombres de pipe por defecto son conocidos, pero los operadores experimentados los personalizan.
Patrones de named pipes conocidos
| Framework | Patrón por defecto | Regex |
|---|---|---|
| Cobalt Strike | \MSSE-{4 digits}-server | \\MSSE-\d{4}-server |
| Cobalt Strike | \postex_*, \status_* | \\(postex_|status_) |
| Metasploit | \msf-pipe-* | \\msf-pipe- |
| PsExec (Impacket) | \RemCom_* | \\RemCom_ |
| Cobalt Strike (named pipe beacon) | \msagent_* | \\msagent_ |
Query Splunk
index=sysmon EventCode IN (17, 18)
| where NOT match(PipeName, "(?i)\\\\lsass|\\\\wkssvc|\\\\ntsvcs|\\\\srvsvc|\\\\atsvc|\\\\epmapper|\\\\spoolss|\\\\browser|\\\\netlogon|\\\\samr")
| regex PipeName="(?i)(MSSE-|msagent_|postex_|status_|msf-pipe|RemCom_|win_svc|ntsvcs_[0-9a-f]{8})"
| stats count values(EventCode) as event_types by Computer, Image, PipeName, User
| sort -count
Query Elastic (KQL)
event.code: ("17" OR "18") AND winlog.event_data.PipeName: (*MSSE-* OR *msagent_* OR *postex_* OR *status_* OR *msf-pipe* OR *RemCom_*)
Análisis de resultados
En este hunt, no se encontraron coincidencias con los patrones conocidos. Esto no significa ausencia de C2: operadores experimentados personalizan los nombres de pipes.
Hunt ampliado: pipes con nombres aleatorios
index=sysmon EventCode=17
| rex field=PipeName "\\\\(?<pipe_basename>[^\\]+)$"
| where len(pipe_basename) > 6 AND match(pipe_basename, "^[a-f0-9]+$")
| stats count by Computer, Image, PipeName
| sort -count
Esta query busca pipes con nombres que parecen hashes hexadecimales, un patrón común en C2 frameworks que aleatorizan los nombres.
Resultado: 4 pipes con nombres hexadecimales, todos creados por el software de gestión de parches corporativo. Falso positivo documentado.
Consolidación de resultados
Resumen del hunt
| Hipótesis | Resultado | Hallazgos | Acciones |
|---|---|---|---|
| PsExec lateral | Sin hallazgos sospechosos | 12 usos legítimos IT | Allowlist + alerta |
| WMI lateral | 1 hallazgo benigno | Admin legítimo fuera de ventana | Regla horaria |
| RDP anomalías | 2 anomalías | Cuenta servicio usada interactivamente | gMSA + alerta svc_* |
| Pass-the-Hash | 1 FP documentado | Software captura accede LSASS | Exclusión + regla activa |
| Named Pipes C2 | Sin hallazgos | 4 FP software parches | Exclusión documentada |
Métricas del hunt
Duración total: 4 horas
Endpoints analizados: 500
Eventos procesados: ~2.4 millones
Hipótesis verificadas: 5
Hallazgos verdaderos: 1 (cuenta de servicio mal usada)
Falsos positivos: 2 (documentados y excluidos)
Reglas de detección nuevas: 4
Reglas mejoradas: 1
Reglas de detección generadas
El valor duradero de un threat hunt son las reglas de detección que convierte en automáticas. De este hunt se derivan:
Regla 1: PsExec desde estación no autorizada
Sigma rule con allowlist de estaciones IT. Severidad: alta.
Regla 2: WMI remoto con PowerShell codificado fuera de horario
Combina Event ID 1 (wmic.exe con /node:) y ventana horaria. Severidad: media.
Regla 3: RDP spray (más de 3 destinos en 1 hora)
Agregación temporal de Event ID 3 puerto 3389. Severidad: alta.
Regla 4: Sesión RDP interactiva con cuenta de servicio
Event ID 4624 LogonType 10 con usuario svc_*. Severidad: crítica.
Regla 5: Acceso a LSASS por proceso no estándar
Event ID 10 con TargetImage lsass.exe, exclusiones documentadas. Severidad: alta.
Mapeo MITRE ATT&CK
| Táctica | Técnica | ID | Hipótesis del hunt |
|---|---|---|---|
| Lateral Movement | Remote Services: SMB/Windows Admin Shares | T1021.002 | H1: PsExec |
| Execution | Windows Management Instrumentation | T1047 | H2: WMI |
| Lateral Movement | Remote Services: Remote Desktop Protocol | T1021.001 | H3: RDP |
| Credential Access | OS Credential Dumping: LSASS Memory | T1003.001 | H4: PtH (prerequisito) |
| Lateral Movement | Use Alternate Authentication Material: Pass the Hash | T1550.002 | H4: PtH |
| Lateral Movement | Lateral Tool Transfer | T1570 | H5: Named Pipes |
| Execution | Inter-Process Communication: Named Pipes | T1559.001 | H5: Named Pipes |
Lecciones y buenas prácticas
Sobre la metodología
-
Hypothesis-driven, no fishing expedition: cada hunt comienza con una hipótesis específica basada en inteligencia de amenazas o en brechas de cobertura de detección. "Buscar cosas raras" no es una hipótesis.
-
Documentar todo, incluidos los falsos positivos: un FP documentado y excluido es tan valioso como un hallazgo verdadero. Reduce el ruido en futuros hunts y en las reglas de detección derivadas.
-
Convertir hallazgos en detección automatizada: si un hunt revela actividad sospechosa, la próxima vez debe detectarse automáticamente. El hunt debería hacerse innecesario para esa hipótesis específica.
-
Baseline antes de cazar: conocer qué es normal en tu entorno es prerequisito. Los 12 usos legítimos de PsExec son la baseline. Sin ella, habrían sido 12 alertas innecesarias.
Sobre la telemetría
-
Sysmon no es opcional para threat hunting: los Security Event Logs de Windows proporcionan autenticación y acceso, pero no procesos con líneas de comando completas, no named pipes, no inyección de procesos. Sysmon llena esos vacíos.
-
Retención mínima de 90 días: los atacantes avanzados tienen dwell times de semanas o meses. Si solo retienes 7 días de logs, no puedes cazar actividad antigua.
-
Correlacionar entre fuentes: ningún evento individual es concluyente. La combinación de Event ID 1 (proceso creado) + Event ID 3 (conexión de red) + Event ID 4624 (autenticación) reconstruye la historia completa.
Sobre las herramientas
-
Las queries de este artículo son un punto de partida: cada entorno tiene su propio ruido y sus propios patrones legítimos. Las exclusiones y los umbrales deben ajustarse al contexto específico.
-
Splunk SPL y Elastic KQL no son intercambiables 1:1: las capacidades de agregación, las funciones de regex y la sintaxis de correlación temporal difieren. Las queries aquí son equivalentes funcionales, no traducciones literales.
-
El hunt no termina con la query: el análisis humano de los resultados es donde se produce el valor. Una query con 0 resultados es un dato (ausencia de evidencia para esa hipótesis). Una query con 10.000 resultados es un problema de filtrado, no un hallazgo.
Preguntas frecuentes
Libros recomendados
Artículos relacionados
Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.