🔵 LABORATORIO DFIR — NIVEL INICIAL / INTERMEDIO
Análisis de Event Logs de Windows para Respuesta a Incidentes
Forense de Windows · Detección de amenazas · SOC / DFIR · GhostAcademy · unfantasmaenelsistema.com
Event ViewerPowerShell
Brute ForcePassword Spraying
Privilege EscalationLOLBins
PersistenciaMITRE ATT&CK
KerberoastingTimeline Analysis
9EJERCICIOS
30+EVENT IDs
9PREGUNTAS
🎯
Objetivos del Laboratorio
¿Qué vas a aprender y practicar?
Este laboratorio práctico te guía por el análisis forense de registros de eventos de Windows (Windows Event Logs) para la detección e investigación de incidentes de seguridad. Los Event Logs son la fuente de telemetría más importante disponible de forma nativa en sistemas Windows y el punto de partida obligatorio en cualquier SOC o investigación DFIR.
Al finalizar serás capaz de:
- Navegar por el Visor de Eventos y entender la estructura de los logs
- Identificar y analizar los Event IDs críticos de seguridad
- Detectar ataques de fuerza bruta, password spraying y movimiento lateral
- Identificar creación de cuentas no autorizadas y escalada de privilegios
- Detectar ejecución sospechosa de procesos, LOLBins y scripts PowerShell maliciosos
- Detectar instalación de servicios y tareas programadas como mecanismos de persistencia
- Correlacionar múltiples eventos para reconstruir la línea de tiempo de un ataque
- Automatizar el análisis con PowerShell (
Get-WinEvent)
📌 CONTEXTOLos Event Logs están siempre activos en cualquier Windows moderno. Un atacante genera eventos inevitablemente: cada autenticación, cada proceso creado, cada modificación de cuenta queda registrada. Aprender a interpretarlos es la habilidad #1 del analista de seguridad defensiva.
F1Estructura
F2Auth
F3Cuentas
F4Procesos
F5Persist.
F6Timeline
F7PowerShell
🧠
Teoría: Estructura y Tipos de Event Logs de Windows
Conceptos fundamentales antes de comenzar
📂CANALES PRINCIPALES DE LOG
| Canal | Archivo .evtx | Contenido relevante para seguridad |
| Security | Security.evtx | Autenticaciones, cuentas, acceso a objetos, política — el más crítico |
| System | System.evtx | Servicios instalados/iniciados, drivers, apagados del sistema |
| Application | Application.evtx | Errores de aplicaciones, eventos de software |
| PowerShell/Operational | ...PowerShell%4Operational.evtx | Scripts PS, ScriptBlock logging (IDs 4103, 4104) — crítico |
| Sysmon/Operational | ...Sysmon%4Operational.evtx | Procesos con hash, conexiones de red, cambios de registro |
| Task Scheduler | ...TaskScheduler%4Operational.evtx | Tareas programadas creadas/ejecutadas |
Los archivos .evtx se encuentran en C:\Windows\System32\winevt\Logs\ y pueden copiarse y analizarse en otro sistema para análisis offline forense.
🔌ANATOMÍA DE UN EVENTO (XML)
<Event>
<s>
<EventID>4624</EventID> <!-- ID del evento -->
<TimeCreated SystemTime="2025-01-15T10:32:47Z"/> <!-- UTC -->
<Computer>WORKSTATION01</Computer> <!-- Dónde ocurrió -->
<Channel>Security</Channel>
</s>
<EventData>
<Data Name="TargetUserName">jdoe</Data> <!-- Cuenta autenticada -->
<Data Name="LogonType">10</Data> <!-- 10 = RDP -->
<Data Name="IpAddress">192.168.1.50</Data> <!-- IP de origen -->
<Data Name="LogonID">0x1a2b3c</Data> <!-- Clave de correlación -->
</EventData>
</Event>
El Logon ID es el campo más valioso para correlación: permite rastrear TODOS los eventos de una misma sesión (procesos creados, cuentas modificadas, etc.) correlacionando por ese identificador único.
📋
Prerrequisitos y Entorno
Lo que necesitas antes de empezar
💻ENTORNO RECOMENDADO
- Sistema operativo: Windows 10/11 Pro o Windows Server 2019/2022 (máquina virtual recomendada)
- Permisos: cuenta de administrador local
- PowerShell 5.1+ (incluido en Windows 10/11)
- Visor de Eventos nativo:
eventvwr.msc
- Opcional: Sysmon de Sysinternals para visibilidad adicional
💡 PARA CLASE — LOGS DE PRÁCTICASi no tienes un entorno con incidentes reales: (1) EVTX Attack Samples — github.com/sbousseaden/EVTX-ATTACK-SAMPLES: logs reales de ataques categorizados por MITRE ATT&CK. (2) CyberDefenders y BlueTeamLabs Online con labs que incluyen .evtx. (3) TryHackMe — módulos de Windows Event Logs y Sysmon.
⚙
Configurar la Auditoría Avanzada de Windows
Sin esto, muchos eventos críticos no se registran
⚠ PROBLEMA FRECUENTEPor defecto Windows NO registra muchos eventos críticos de seguridad. La auditoría debe configurarse explícitamente. Si un Event ID no aparece, la categoría de auditoría no está habilitada.
1
Verificar configuración actual CMD
# Ver todas las categorías
auditpol /get /category:*
# Ver las relevantes
auditpol /get /category:"Account Logon"
auditpol /get /category:"Logon/Logoff"
auditpol /get /category:"Account Management"
auditpol /get /category:"Detailed Tracking"
2
Activar categorías esenciales ADMIN REQUERIDO
# Inicio/cierre de sesión
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable
auditpol /set /subcategory:"Special Logon" /success:enable
# Gestión de cuentas
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Security Group Management" /success:enable /failure:enable
# Creación de procesos (necesario para Event ID 4688)
auditpol /set /subcategory:"Process Creation" /success:enable
# Cambios de política
auditpol /set /subcategory:"Audit Policy Change" /success:enable /failure:enable
3
Habilitar Command Line en Event ID 4688 REGISTRO DE WINDOWS
# Necesario para ver los argumentos de cada proceso (muy importante)
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v ProcessCreationIncludeCmdLine_Enabled /t REG_DWORD /d 1 /f
4
Habilitar PowerShell ScriptBlock Logging (Event ID 4104) POWERSHELL — CRÍTICO
Captura el contenido completo de scripts PowerShell ejecutados, incluso ofuscados. Fundamental para detectar ataques fileless.
# Event ID 4104 - ScriptBlock logging
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 /f
# Event ID 4103 - Module logging
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" /v EnableModuleLogging /t REG_DWORD /d 1 /f
✓ RECOMENDADO — INSTALAR SYSMONSysmon proporciona telemetría más detallada: hashes SHA-256 de procesos, conexiones de red por proceso, cambios de registro. Instalar: sysmon64 -accepteula -i sysmon-config.xml (usar config de SwiftOnSecurity en GitHub)
💻
Ejercicio 1 — El Visor de Eventos
Objetivo: familiarizarse con la interfaz y estructura de los logs
1
Abrir el Visor de Eventos ACCESO
# Win+R:
eventvwr.msc
# Desde CMD:
eventvwr
# Desde PowerShell:
Start-Process eventvwr.msc
2
Explorar la jerarquía NAVEGACIÓN
Panel izquierdo:
- Registros de Windows → Aplicación, Seguridad, Sistema
- Registros de aplicaciones y servicios → Microsoft → Windows → PowerShell, Sysmon...
Haz clic en Seguridad. Cada evento muestra: nivel, fecha, origen, ID y categoría.
3
Examinar el detalle de un evento ANATOMÍA
Doble clic en cualquier evento:
- Pestaña General: descripción legible con datos rellenos
- Pestaña Detalles → XML: el XML raw con todos los campos exactos — el más útil para forense
4
Exportar logs para análisis offline PRESERVACIÓN
# Clic derecho sobre el log -> 'Guardar todos los eventos como...' -> .evtx
# Con PowerShell (más controlado):
wevtutil epl Security C:\Evidence\Security_$(Get-Date -Format yyyyMMdd).evtx
wevtutil epl System C:\Evidence\System_$(Get-Date -Format yyyyMMdd).evtx
# Calcular hashes (cadena de custodia)
Get-FileHash C:\Evidence\*.evtx -Algorithm SHA256 | Format-Table
❓ Pregunta
Al abrir el log de Seguridad ves que tiene solo 20MB y los eventos más antiguos son de hace 2 días. En un sistema en producción, ¿qué significaría esto?
💡 Busca el Event ID 1102 y piensa en por qué un log podría ser tan pequeño.
Ver respuesta
Puede indicar borrado intencional de logs. El Event ID 1102 (log de seguridad borrado) se registra cuando alguien borra el log. Otro motivo: tamaño máximo muy pequeño. Investigar: (1) buscar Event IDs 1102 y 104, (2) verificar tamaño máximo configurado, (3) revisar si hay logs en SIEM centralizado o backup.
🔒
Ejercicio 2 — Eventos de Autenticación
Objetivo: analizar el ciclo completo de inicio y cierre de sesión
🔑EVENT IDs DE AUTENTICACIÓN CLAVE
| Event ID | Nombre | Cuándo ocurre | Relevancia |
| 4624 | Inicio de sesión correcto | Autenticación exitosa | Crítico — ver Logon Type |
| 4625 | Error de inicio de sesión | Autenticación fallida | Crítico — fuerza bruta, spraying |
| 4634 | Cierre de sesión | Fin de sesión | Alto — correlacionar con 4624 |
| 4648 | Credenciales explícitas | runas, PsExec, movimiento lateral | Crítico — lateral movement |
| 4672 | Privilegios especiales asignados | Admin se autentica | Alto — siempre acompaña 4624 de admin |
| 4769 | Ticket servicio Kerberos solicitado | Acceso a servicio del dominio | Crítico — Kerberoasting (muchos + RC4) |
| 4776 | Validación NTLM | Auth NTLM | Crítico — Pass-the-Hash, NTLM relay |
1
Examinar campos críticos del Event ID 4624 ANÁLISIS
# Campos que SIEMPRE debes revisar:
#
# LogonType -> Vector de acceso (ver tabla de tipos)
# TargetUserName -> Cuenta que se autenticó
# LogonID -> ID Único de sesión (correlación con otros eventos)
# IpAddress -> IP de origen (- o ::1 = local)
# WorkstationName -> Equipo de origen
# AuthPackageName -> NTLM / Kerberos / Negotiate
# ElevatedToken -> 1 = sesión elevada (admin)
2
Buscar inicios de sesión RDP (Logon Type 10) DETECCIÓN RDP
Get-WinEvent -FilterHashtable @{{
LogName = 'Security'
Id = 4624
}} | Where-Object {{ $_.Properties[8].Value -eq 10 }} |
ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Usuario = $_.Properties[5].Value
IP_Origen = $_.Properties[18].Value
Workstation= $_.Properties[11].Value
LogonID = $_.Properties[7].Value
}}
}} | Sort-Object Tiempo | Format-Table -AutoSize
3
Detectar uso de credenciales explícitas (4648) LATERAL MOVEMENT
# Indica runas, PsExec, movimiento lateral
Get-WinEvent -FilterHashtable @{{ LogName='Security'; Id=4648 }} |
ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Cuenta_Origen = $_.Properties[1].Value
Cuenta_Objetivo = $_.Properties[5].Value
Servidor_Destino = $_.Properties[8].Value
Proceso = $_.Properties[11].Value
}}
}} | Format-Table -AutoSize
❓ Pregunta
Encuentras muchos Event ID 4624 con LogonType=3 desde la IP 10.10.5.22 durante el fin de semana. El usuario es 'svc_backup'. ¿Es sospechoso?
💡 Logon Type 3 es acceso de red (SMB). Piensa en qué hace una cuenta de servicio de backup y en qué horario debería trabajar.
Ver respuesta
Puede ser legítimo o sospechoso. Señales de alarma: (1) backup no programado ese fin de semana, (2) IP 10.10.5.22 no es el servidor de backup habitual, (3) la cuenta accede a recursos no relacionados con backup. Investigar: correlacionar el Logon ID de esos 4624 con 4688 para ver qué procesos ejecutó la cuenta en esa sesión.
🔎
Ejercicio 3 — Filtrado y Búsqueda Avanzada
Objetivo: encontrar eventos específicos entre millones de entradas
1
Filtro básico del Visor de Eventos GUI
- Selecciona Seguridad en el panel izquierdo
- Clic en "Filtrar registro actual..."
- Escribe el ID en "Incluye/Excluye identificadores": ej.
4625
- Para múltiples IDs sepáralos con comas:
4624, 4625, 4648
- Establece un rango de fechas en "Fecha y hora"
2
Filtros XPath avanzados XPATH
<!-- Filtrar 4625 de un usuario específico -->
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[(EventID=4625)]] and
*[EventData[Data[@Name='TargetUserName']='administrator']]
</Select>
</Query>
</QueryList>
<!-- Múltiples IDs + rango de tiempo -->
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[(EventID=4624 or EventID=4625 or EventID=4648)
and TimeCreated[@SystemTime>='2025-01-15T00:00:00Z'
and @SystemTime<='2025-01-15T23:59:59Z']]]
</Select>
</Query>
</QueryList>
3
Análisis de archivos .evtx offline OFFLINE
# Analizar archivo .evtx copiado de otro equipo
Get-WinEvent -Path 'C:\Evidence\Security.evtx' -FilterHashtable @{{
Id = @(4624, 4625, 4648)
}} | ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
EventID = $_.Id
Usuario = $_.Properties[5].Value
IP = $_.Properties[18].Value
}}
}} | Export-Csv 'C:\Evidence\auth_events.csv' -NoTypeInformation
❓ Pregunta
Recibes una alerta de que la cuenta 'mgarcia' pudo ser comprometida el 20 de enero entre 14:00 y 16:00. ¿Qué Event IDs incluirías en el filtro?
💡 Cubre autenticación, actividad y posibles cambios. Las horas en XPath son UTC.
Ver respuesta
Incluiría: 4624 (logons exitosos), 4625 (fallidos), 4648 (credenciales explícitas), 4634 (cierres), 4672 (privilegios especiales). Si sospecho escalada: 4720 (cuenta creada) y 4732 (añadido a grupo). Filtrar por TargetUserName='mgarcia' y el rango horario para reconstruir qué hizo la cuenta exactamente.
🔴
Ejercicio 4 — Detección de Ataques de Fuerza Bruta y Password Spraying
Objetivo: identificar intentos de acceso masivos no autorizados
🚨 ESCENARIO — SERVIDOR BAJO ATAQUE
El SOC recibe alerta: más de 200 eventos 4625 en el servidor FILESERVER01 en 30 minutos. Determina si es fuerza bruta, password spraying o un falso positivo.
1
Cuantificar y clasificar los fallos VOLUMEN
$inicio = (Get-Date).AddHours(-2)
$fallos = Get-WinEvent -FilterHashtable @{{
LogName='Security'; Id=4625; StartTime=$inicio
}} | ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Usuario = $_.Properties[5].Value
IP_Origen = $_.Properties[19].Value
SubStatus = $_.Properties[9].Value
LogonType = $_.Properties[10].Value
}}
}}
Write-Host "Total fallos: $($fallos.Count)"
# Top IPs atacantes
$fallos | Group-Object IP_Origen |
Sort-Object Count -Desc | Select-Object -First 10 |
Format-Table Count, Name -AutoSize
# Top usuarios atacados
$fallos | Group-Object Usuario |
Sort-Object Count -Desc | Select-Object -First 10 |
Format-Table Count, Name -AutoSize
2
Distinguir fuerza bruta de password spraying PATRÓN
# FUERZA BRUTA: muchos intentos en UN usuario desde UNA IP
# SPRAYING: pocos intentos en MUCHOS usuarios desde UNA IP
$fallos | Group-Object IP_Origen | ForEach-Object {{
$usuariosUnicos = ($_.Group.Usuario | Sort-Object -Unique).Count
[PSCustomObject]@{{
IP = $_.Name
TotalFallos = $_.Count
UsuariosDistintos= $usuariosUnicos
Patron = if ($usuariosUnicos -gt 10) {{
'PASSWORD SPRAYING'
}} else {{'FUERZA BRUTA'}}
}}
}} | Format-Table -AutoSize
3
Analizar el SubStatus para entender la causa ERRORES
# SubStatus más comunes:
# 0xC000006A = Contraseña incorrecta (usuario EXISTE)
# 0xC0000064 = Usuario NO existe (enumeración)
# 0xC000006F = Fuera del horario permitido
# 0xC0000072 = Cuenta deshabilitada
# 0xC0000234 = Cuenta bloqueada (por ataques previos)
$fallos | Group-Object SubStatus | Sort-Object Count -Desc |
ForEach-Object {{
$sig = switch ($_.Name) {{
'0xc000006a' {{'Contraseña incorrecta (usuario existe)'}}
'0xc0000064' {{'Usuario NO existe (enumeración)'}}
'0xc0000072' {{'Cuenta deshabilitada'}}
'0xc0000234' {{'Cuenta bloqueada (bruteforce previo)'}}
default {{"Código: $($_.Name)"}}
}}
[PSCustomObject]@{{ Significado=$sig; Total=$_.Count }}
}} | Format-Table -AutoSize
4
Detectar éxito tras los fallos (brute force completado) CRÍTICO
$ips_atacantes = $fallos.IP_Origen | Sort-Object -Unique
$exitos = Get-WinEvent -FilterHashtable @{{
LogName='Security'; Id=4624; StartTime=$inicio
}} | ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Usuario = $_.Properties[5].Value
IP_Origen= $_.Properties[18].Value
LogonType= $_.Properties[8].Value
}}
}} | Where-Object {{ $_.IP_Origen -in $ips_atacantes }}
if ($exitos) {{
Write-Host "ALERTA CRITICA: login exitoso desde IP atacante!" -ForegroundColor Red
$exitos | Format-Table -AutoSize
}} else {{
Write-Host "Sin logins exitosos desde IPs atacantes" -ForegroundColor Green
}}
❓ Pregunta
Encuentras 500 eventos 4625 con SubStatus 0xC0000064 desde la IP 45.33.32.156. ¿Qué técnica indica y por qué la diferencia con 0xC000006A es importante?
💡 Piensa en qué hace un atacante antes de intentar la contraseña correcta.
Ver respuesta
0xC0000064 indica que el usuario no existe: enumeración de usuarios para descubrir qué cuentas son válidas, típicamente previa a un password spraying. 0xC000006A indica usuario válido con contraseña incorrecta, mucho más peligroso porque el atacante ya sabe qué cuentas existen y está adivinando la contraseña.
👤
Ejercicio 5 — Gestión de Cuentas y Privilegios
Objetivo: detectar creación de cuentas no autorizadas y escalada de privilegios
🚨 ESCENARIO — CUENTA BACKDOOR
El viernes a las 23:47 se creó la cuenta 'support_temp' y se añadió al grupo Administrators. Nadie del equipo de TI la recuerda. Reconstruye quién la creó y desde dónde.
👤EVENT IDs DE GESTIÓN DE CUENTAS
| Event ID | Descripción | Relevancia |
| 4720 | Cuenta de usuario creada | Backdoor de cuenta |
| 4726 | Cuenta eliminada | Borrado de evidencia |
| 4738 | Cuenta modificada | Cambio de contraseña, flags |
| 4740 | Cuenta bloqueada | Confirma ataque previo |
| 4728 | Miembro añadido a grupo global (AD) | Escalada (Domain Admins) |
| 4732 | Miembro añadido a grupo local | Escalada (Administrators) |
1
Detectar creación de cuentas BÚSQUEDA
$hace7dias = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{{
LogName='Security'; Id=4720; StartTime=$hace7dias
}} | ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Nueva_Cuenta = $_.Properties[0].Value # TargetUserName
Creada_Por = $_.Properties[4].Value # SubjectUserName
Logon_ID = $_.Properties[7].Value # Para correlación
}}
}} | Format-Table -AutoSize
2
Verificar adición al grupo Administrators ESCALADA
# Event ID 4732 - grupo local
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4732}} |
Where-Object {{ $_.Properties[2].Value -like '*Admin*' }} |
ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Miembro = $_.Properties[0].Value
Grupo = $_.Properties[2].Value
Por_Quien = $_.Properties[6].Value
}}
}} | Format-Table -AutoSize
# Para dominio - Event ID 4728 (grupos globales)
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4728}} |
Where-Object {{ $_.Properties[2].Value -like '*Domain Admin*' }} |
ForEach-Object {{
Write-Host "ALERTA: $($_.Properties[0].Value) -> $($_.Properties[2].Value)" -ForegroundColor Red
}}
3
Rastrear la sesión origen por Logon ID CORRELACIÓN
$logonId = '0x1a2b3c' # Del campo SubjectLogonId del evento 4720
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4624}} |
Where-Object {{ $_.Properties[7].Value -eq $logonId }} |
ForEach-Object {{
Write-Host "Sesión origen:"
Write-Host " Usuario: $($_.Properties[5].Value)"
Write-Host " IP: $($_.Properties[18].Value)"
Write-Host " Tipo: $($_.Properties[8].Value) (10=RDP, 3=Red)"
Write-Host " Hora: $($_.TimeCreated)"
}}
❓ Pregunta
El evento 4720 muestra que la cuenta fue creada por SYSTEM (SubjectLogonId = 0x3e7). ¿Es más preocupante que si la creara un usuario normal?
💡 0x3e7 es el Logon ID fijo de la sesión SYSTEM. ¿Qué tipo de proceso corre como SYSTEM?
Ver respuesta
Es significativamente más preocupante. Que SYSTEM cree una cuenta indica: (1) explotación de vulnerabilidad de elevación de privilegios, (2) un servicio malicioso corriendo como SYSTEM, (3) malware con privilegios de sistema. Investigar: Event ID 4688 alrededor de esa hora buscando procesos sospechosos ejecutados como SYSTEM.
⚙
Ejercicio 6 — Ejecución de Procesos Sospechosos (4688)
Objetivo: detectar malware, LOLBins y PowerShell malicioso
📌 REQUISITOEl Event ID 4688 requiere auditoría de Process Creation habilitada + command line auditing activado (Ejercicio de Configuración). Sin esto el campo CommandLine estará vacío.
1
Detectar comandos de reconocimiento RECONOCIMIENTO
$recon = @('whoami','net user','net group','net localgroup',
'ipconfig','systeminfo','tasklist','netstat',
'nltest','wmic','reg query','dsquery')
Get-WinEvent -FilterHashtable @{{
LogName='Security'; Id=4688
StartTime=(Get-Date).AddHours(-24)
}} | ForEach-Object {{
$cmd = $_.Properties[8].Value
$usr = $_.Properties[1].Value
$padre = $_.Properties[13].Value
foreach ($r in $recon) {{
if ($cmd -like "*$r*") {{
Write-Host "[RECON] $r" -ForegroundColor Yellow
Write-Host " $($_.TimeCreated) | Usuario: $usr"
Write-Host " Padre: $padre"
Write-Host " CMD: $cmd"
}}
}}
}}
2
Detectar LOLBins LIVING-OFF-THE-LAND
# Ejecutables legítimos abusados con fines maliciosos
$lol = @('certutil','mshta','regsvr32.exe','wscript',
'cscript','rundll32','bitsadmin','expand.exe')
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4688}} |
ForEach-Object {{
$proc = [IO.Path]::GetFileName($_.Properties[5].Value).ToLower()
if ($proc -in $lol) {{
[PSCustomObject]@{{
Hora = $_.TimeCreated
Usuario = $_.Properties[1].Value
LOLBin = $proc
CmdLine = $_.Properties[8].Value
Padre = $_.Properties[13].Value
}}
}}
}} | Format-Table -AutoSize -Wrap
3
Detectar PowerShell sospechoso POWERSHELL ABUSE
# -EncodedCommand (-enc) : ejecuta base64 (evasion de logging)
# -WindowStyle Hidden : oculta ventana
# IEX / DownloadString : descarga y ejecuta
# bypass : evade política de ejecución
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4688}} |
Where-Object {{
$c = $_.Properties[8].Value
$c -match 'powershell' -and (
$c -match '-[Ee][Nn][Cc]' -or
$c -match 'IEX|Invoke-Expression' -or
$c -match 'DownloadString|DownloadFile' -or
$c -match '-[Ww]indow[Ss]tyle\s+[Hh]idden' -or
$c -match 'bypass'
)
}} | ForEach-Object {{
Write-Host "[PS SOSPECHOSO] $($_.TimeCreated)" -ForegroundColor Red
Write-Host " Usuario: $($_.Properties[1].Value)"
Write-Host " CMD: $($_.Properties[8].Value)" -ForegroundColor Yellow
}}
❓ Pregunta
En los logs de 4688 ves que excel.exe tiene como hijo a powershell.exe, que ejecuta cmd.exe /c whoami. ¿Qué técnica indica?
💡 Piensa en qué hace Excel para ejecutar PowerShell. ¿Macros?
Ver respuesta
Macro maliciosa de Excel (Maldoc / VBA macro attack). El flujo clásico: documento Office → shell → reconocimiento. El atacante envía un documento con macro que, al habilitarse, descarga y ejecuta malware. La cadena padre-hijo es uno de los indicadores más fiables. Otros sospechosos: winword.exe → powershell.exe, outlook.exe → cmd.exe.
📡
Ejercicio 7 — Servicios y Mecanismos de Persistencia
Objetivo: detectar servicios maliciosos y tareas programadas
📡EVENT IDs DE PERSISTENCIA
| Event ID | Canal | Descripción |
| 4697 | Security | Servicio instalado en el sistema |
| 7045 | System | Nuevo servicio instalado (incluye ruta del ejecutable) |
| 7040 | System | Tipo de inicio de servicio cambiado |
| 4698 | Security | Tarea programada creada |
| 4702 | Security | Tarea programada modificada |
| 1102 | Security | Log de seguridad borrado — anti-forense crítico |
| 104 | System | Log del sistema borrado — anti-forense crítico |
1
Detectar instalación de servicios SERVICIOS
# Event ID 7045 del canal System (más detallado que 4697)
Get-WinEvent -FilterHashtable @{{LogName='System'; Id=7045}} |
ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Nombre = $_.Properties[0].Value # ServiceName
Ruta = $_.Properties[1].Value # ImagePath
Inicio = $_.Properties[2].Value # StartType
Cuenta = $_.Properties[4].Value # AccountName
}}
}} | Sort-Object Tiempo -Desc | Format-Table -AutoSize -Wrap
# RUTAS SOSPECHOSAS:
# C:\Users\*\AppData\Temp\...
# C:\ProgramData\...
# Nombres que imitan servicios (svchost32.exe, lsass.exe)
2
Detectar tareas programadas SCHEDULED TASKS
# Event ID 4698 - Tarea programada creada
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4698}} |
ForEach-Object {{
[PSCustomObject]@{{
Tiempo = $_.TimeCreated
Usuario = $_.Properties[1].Value
Tarea = $_.Properties[4].Value
}}
}} | Sort-Object Tiempo -Desc | Format-Table -AutoSize
3
Detectar borrado de logs (anti-forense) ANTI-FORENSICS
# Event ID 1102 - Log de Seguridad borrado
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=1102}} |
ForEach-Object {{
Write-Host "CRITICO: Log BORRADO" -ForegroundColor Red
Write-Host " Cuando: $($_.TimeCreated)"
Write-Host " Por quien: $($_.Properties[1].Value)"
}}
# Event ID 104 - Log del Sistema borrado
Get-WinEvent -FilterHashtable @{{LogName='System'; Id=104}} |
ForEach-Object {{
Write-Host "CRITICO: Log SISTEMA borrado - $($_.TimeCreated)" -ForegroundColor Red
}}
❓ Pregunta
Encuentras Event ID 7045 con ImagePath = C:\Users\Public\svchost32.exe. ServiceName = 'Windows Update Helper'. ¿Qué te llama la atención?
💡 Fijate en la ruta, el nombre del ejecutable y el nombre del servicio.
Ver respuesta
Múltiples alarmas: (1) Ruta sospechosa: servicios legítimos de Windows están en System32, nunca en Users\Public. (2) svchost32.exe imita svchost.exe: el real nunca tiene '32'. (3) 'Windows Update Helper' no existe como servicio nativo. Para confirmar: calcular SHA-256 en VirusTotal, verificar firma digital, buscar en 4688 si fue creado por otro proceso.
🔗
Ejercicio 8 — Correlación de Eventos y Línea de Tiempo
Objetivo: reconstruir la secuencia completa de un incidente
🚨 ESCENARIO — INCIDENTE COMPLETO
El servidor muestra actividad inusual el martes por la noche. Reconstruye: (1) cómo entró el atacante, (2) reconocimiento, (3) escalada de privilegios, (4) persistencia, (5) borrado de evidencia.
1
Construir una línea de tiempo unificada TIMELINE
$inicio = (Get-Date).AddDays(-2)
$IDS_SEC = @(1102,4624,4625,4648,4672,4688,4697,4698,4720,4728,4732)
$IDS_SYS = @(7045,7040,104)
$tl = @()
foreach ($id in $IDS_SEC) {{
try {{
Get-WinEvent -FilterHashtable @{{LogName='Security';Id=$id;StartTime=$inicio}} -EA Stop |
ForEach-Object {{
$tl += [PSCustomObject]@{{
Tiempo=$_.TimeCreated; EID=$id; Canal='Security'
Desc=$_.Message.Split('.')[0].Trim().Substring(0,[Math]::Min(75,$_.Message.Length))
}}
}}
}} catch {{}}
}}
foreach ($id in $IDS_SYS) {{
try {{
Get-WinEvent -FilterHashtable @{{LogName='System';Id=$id;StartTime=$inicio}} -EA Stop |
ForEach-Object {{
$tl += [PSCustomObject]@{{Tiempo=$_.TimeCreated;EID=$id;Canal='System'
Desc=$_.Message.Split('.')[0].Trim().Substring(0,[Math]::Min(75,$_.Message.Length))}}
}}
}} catch {{}}
}}
$tl | Sort-Object Tiempo | Format-Table Tiempo,EID,Canal,Desc -AutoSize -Wrap
$tl | Sort-Object Tiempo | Export-Csv 'C:\Forensics\timeline.csv' -NoTypeInformation
2
Rastrear una sesión completa por Logon ID CORRELACIÓN
$logonId = '0x1234ab' # Del campo LogonID del evento 4624 sospechoso
# Procesos creados en esa sesión
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4688}} |
Where-Object {{ $_.Properties[3].Value -eq $logonId }} |
ForEach-Object {{
Write-Host "PROCESO: $($_.Properties[5].Value)"
Write-Host "CMDLINE: $($_.Properties[8].Value)"
Write-Host "HORA: $($_.TimeCreated)"
Write-Host ""
}}
# Cuentas creadas en esa sesión
Get-WinEvent -FilterHashtable @{{LogName='Security'; Id=4720}} |
Where-Object {{ $_.Properties[7].Value -eq $logonId }} |
ForEach-Object {{
Write-Host "CUENTA CREADA: $($_.Properties[0].Value)" -ForegroundColor Red
}}
❓ Pregunta
En la sesión correlacionada por Logon ID ves: net user, net localgroup, whoami /all, creación de cuenta, adición a Administrators. ¿Qué fases de MITRE ATT&CK representa cada acción?
💡 MITRE ATT&CK organiza las técnicas en Tácticas.
Ver respuesta
net user/localgroup/whoami → Discovery (TA0007), Account Discovery (T1087). Creación de cuenta → Persistence (TA0003), Create Account (T1136.001). Añadir a Administrators → Privilege Escalation (TA0004), Account Manipulation (T1098). Logon Type 3 sugiere movimiento lateral (TA0008).
💻
Ejercicio 9 — Automatización con PowerShell
Objetivo: scripts reutilizables para análisis eficiente y automatizado
1
Métodos de filtrado de Get-WinEvent FUNDAMENTOS
# MÉTODO 1: FilterHashtable (más rápido)
Get-WinEvent -FilterHashtable @{{
LogName='Security'; Id=4624
StartTime=(Get-Date).AddHours(-24)
}}
# MÉTODO 2: FilterXml (control total con XPath)
$x = '<QueryList><Query Id="0" Path="Security"><Select Path="Security">*[System[(EventID=4625)]]</Select></Query></QueryList>'
Get-WinEvent -FilterXml $x
# MÉTODO 3: Archivo .evtx offline
Get-WinEvent -Path 'C:\Evidence\Security.evtx' -FilterHashtable @{{Id=4624}}
# MÉTODO 4: Remoto (requiere WinRM)
Get-WinEvent -ComputerName 'SERVER01','DC01' -FilterHashtable @{{LogName='Security';Id=4720}}
2
Script de triáje rápido de seguridad TRIAGE
# ============================================
# TRIAJE RAPIDO DE SEGURIDAD
# GhostAcademy - unfantasmaenelsistema.com
# ============================================
param([int]$H=24, [string]$Equipo=$env:COMPUTERNAME)
Write-Host "=== TRIAJE: $Equipo | Ultimas $H horas ==" -ForegroundColor Cyan
$ini=(Get-Date).AddHours(-$H)
# [1] Fallos
Write-Host "`n[1] FALLOS 4625:" -ForegroundColor Yellow
try {{
$f=Get-WinEvent -CN $Equipo -FH @{{LogName='Security';Id=4625;StartTime=$ini}} -EA Stop
Write-Host " Total: $($f.Count)"
$f|Group-Object {{$_.Properties[19].Value}}|Sort Count -Desc|Select -F 5|
%{{Write-Host " IP $($_.Name): $($_.Count)"}}
}} catch {{Write-Host " Sin fallos"}}
# [2] Cuentas creadas
Write-Host "`n[2] CUENTAS 4720:" -ForegroundColor Yellow
try {{
$c=Get-WinEvent -CN $Equipo -FH @{{LogName='Security';Id=4720;StartTime=$ini}} -EA Stop
if($c){{Write-Host " ALERTA: $($c.Count) cuentas!" -ForegroundColor Red
$c|%{{Write-Host " $($_.Properties[0].Value) por $($_.Properties[4].Value)"}} }}
else{{Write-Host " Ninguna"}}
}} catch {{Write-Host " Sin acceso"}}
# [3] Servicios
Write-Host "`n[3] SERVICIOS 7045:" -ForegroundColor Yellow
try {{
$s=Get-WinEvent -CN $Equipo -FH @{{LogName='System';Id=7045;StartTime=$ini}} -EA Stop
if($s){{Write-Host " ALERTA: $($s.Count) servicios!" -ForegroundColor Red
$s|%{{Write-Host " $($_.Properties[0].Value): $($_.Properties[1].Value)"}} }}
else{{Write-Host " Ninguno"}}
}} catch {{}}
# [4] Logs borrados
Write-Host "`n[4] LOGS BORRADOS:" -ForegroundColor Yellow
try {{
$b=Get-WinEvent -CN $Equipo -FH @{{LogName='Security';Id=1102;StartTime=$ini}} -EA Stop
if($b){{Write-Host " CRITICO: LOGS BORRADOS!" -ForegroundColor Red}}
else{{Write-Host " OK"}}
}} catch {{Write-Host " OK"}}
Write-Host "`n=== FIN TRIAJE ===" -ForegroundColor Cyan
3
Analizar múltiples hosts en paralelo ESCALA
$servidores = @('SRV01','SRV02','DC01','FILESERVER')
$resultados = $servidores | ForEach-Object -Parallel {{
$srv = $_
$ini = (Get-Date).AddHours(-24)
try {{
$fallos = (Get-WinEvent -CN $srv -FH @{{
LogName='Security'; Id=4625; StartTime=$ini
}} -EA Stop).Count
[PSCustomObject]@{{Servidor=$srv; Fallos4625=$fallos; Estado='OK'}}
}} catch {{
[PSCustomObject]@{{Servidor=$srv; Fallos4625=0; Estado='Sin acceso'}}
}}
}} -ThrottleLimit 5
$resultados | Sort-Object Fallos4625 -Desc | Format-Table -AutoSize
❓ Pregunta
¿Cuál es la diferencia entre FilterHashtable y FilterXml en Get-WinEvent? ¿Cuándo usar cada uno?
💡 Piensa en flexibilidad vs velocidad y qué permite filtrar cada uno.
Ver respuesta
FilterHashtable es más rápido porque Windows filtra a nivel del motor de logging antes de devolver datos — ideal para filtros simples (por ID, fecha, nivel). FilterXml con XPath permite filtrar por valores de campos dentro del EventData (ej: solo eventos con un TargetUserName específico o una IP concreta) — más flexible pero algo más lento. Regla práctica: FilterHashtable para volumen rápido, luego Where-Object o FilterXml cuando necesitas precisión de campo.
📚
Referencia: Event IDs de Seguridad Esenciales
Cheat sheet para SOC analysts y DFIR
| Event ID | Canal | Descripción | TTPs relacionadas |
| 1102 | Security | Log de auditoría borrado | Anti-forensics |
| 104 | System | Log del sistema borrado | Anti-forensics |
| 4624 | Security | Inicio de sesión correcto — ver Logon Type | Acceso inicial, movimiento lateral |
| 4625 | Security | Error de inicio de sesión | Fuerza bruta, password spraying |
| 4634 | Security | Cierre de sesión | Duración de sesiones |
| 4648 | Security | Inicio con credenciales explícitas | Movimiento lateral, runas, PsExec |
| 4672 | Security | Privilegios especiales asignados | Uso de cuentas admin |
| 4688 | Security | Nuevo proceso creado (necesita configuración) | Ejecución de malware, LOLBins |
| 4697 | Security | Servicio instalado | Persistencia como servicio |
| 4698 | Security | Tarea programada creada | Persistencia por scheduled task |
| 4720 | Security | Cuenta de usuario creada | Persistencia de cuenta backdoor |
| 4726 | Security | Cuenta eliminada | Eliminación de evidencia |
| 4728 | Security | Miembro añadido a grupo global (AD) | Escalada (Domain Admins) |
| 4732 | Security | Miembro añadido a grupo local | Escalada (Administrators) |
| 4740 | Security | Cuenta bloqueada | Confirma ataque de fuerza bruta |
| 4768 | Security | Kerberos TGT solicitado | Golden Ticket detection, AS-REP Roasting |
| 4769 | Security | Ticket de servicio Kerberos solicitado | Kerberoasting (muchos + RC4=0x17) |
| 4771 | Security | Fallo pre-auth Kerberos | Fuerza bruta en dominio |
| 4776 | Security | Validación NTLM | Pass-the-Hash, NTLM relay |
| 7045 | System | Nuevo servicio instalado | Persistencia como servicio |
| 4104 | PS/Operational | ScriptBlock logging — contenido completo del script | Scripts ofuscados, fileless malware |
🔑
Tipos de Inicio de Sesión (Logon Types)
Campo crítico en eventos 4624 y 4625 — determina el vector de acceso
| Tipo | Nombre | Descripción | Relevancia forense |
| 2 | Interactive | Logon físico en la consola (teclado + pantalla) | Acceso físico o KVM |
| 3 | Network | Acceso de red: SMB, WMI, recursos compartidos | Movimiento lateral, acceso a shares |
| 4 | Batch | Tarea programada ejecutada por el scheduler | Persistencia por scheduled task |
| 5 | Service | Inicio de sesión de un servicio de Windows | Servicios maliciosos |
| 7 | Unlock | Desbloqueo de estación de trabajo | Actividad del usuario |
| 8 | NetworkCleartext | Credenciales en texto plano por la red | Riesgo captura de credenciales |
| 9 | NewCredentials | runas con /netonly | Movimiento lateral |
| 10 | RemoteInteractive | Acceso RDP — escritorio remoto interactivo | Crítico — RDP desde IPs externas |
| 11 | CachedInteractive | Logon con credenciales cacheadas (sin DC) | Sistemas fuera de red de dominio |
⚠
Códigos de Error de Autenticación (SubStatus)
Campo del Event ID 4625 que explica el motivo del fallo
| SubStatus | Significado | Interpretación |
0xC000006A | BAD_PASSWORD | Contraseña incorrecta — el usuario EXISTE. Fuerza bruta o spraying. |
0xC0000064 | NO_SUCH_USER | El usuario NO EXISTE. Enumeración de usuarios o typo. |
0xC000006F | INVALID_LOGON_HOURS | Fuera del horario permitido. Restricción horaria activa. |
0xC0000070 | INVALID_WORKSTATION | Acceso desde equipo no autorizado. |
0xC0000072 | ACCOUNT_DISABLED | Cuenta deshabilitada. Reutilización de cuentas antiguas. |
0xC0000234 | ACCOUNT_LOCKED_OUT | Cuenta bloqueada. Confirma fuerza bruta previa. |
0xC0000193 | ACCOUNT_EXPIRED | Cuenta expirada. |
0xC0000071 | PASSWORD_EXPIRED | Contraseña expirada. Normal en rotación de contraseñas. |