Cómo hacer un seguimiento de los eventos importantes de seguridad de Windows con PowerShell


Muchas organizaciones confían en las tecnologías de Microsoft para realizar su trabajo. Al mismo tiempo, los actores de amenazas pueden explotar sistemas operativos como Windows. Afortunadamente, Windows registra eventos de seguridad del sistema operativo para ayudarlo a rastrear este comportamiento.

Los eventos de seguridad producidos por Windows son un recurso crítico en el proceso de respuesta a incidentes. Herramientas como el Visor de eventos de Windows de Microsoft le proporcionan el acceso necesario para revisar los eventos capturados, pero detectar anomalías manualmente mediante la búsqueda en un registro abarrotado es poco realista.

En esta publicación, aprenderá cómo rastrear posibles brechas de seguridad en Windows mediante el aprendizaje sobre políticas de auditoría, registros de eventos de Windows y análisis de eventos de seguridad con PowerShell.

Prerrequisitos

Este artículo tiene como objetivo proporcionar información que le enseñe cómo analizar eventos de seguridad de Windows con PowerShell. Si desea seguir cualquiera de las demostraciones, necesitará:

  • A Windows 10+ PC – This PC will be used to generate and track down potential security events in the event log. This tutorial will be using Windows PowerShell 5.1.
  • Derechos de administrador en la PC con Windows
  • A PowerShell code editor such PowerShell ISE or Visual Studio (VS) Code.

Dónde Windows Almacena Eventos de Seguridad

Cuando se realiza una acción en un sistema operativo Windows, Windows registra la acción como un evento en uno o más registros de eventos. Los registros de eventos de Windows se almacenan en el sistema de archivos, por defecto, en el directorio %SystemRoot%\system32\winevt\logs. Esta ubicación puede cambiarse modificando la subclave del registro EventLog del respectivo registro de eventos.

Si desea ver dónde se almacenan los registros de eventos más destacados (Application, Security y System) en su sistema, copie y pegue el siguiente código en una consola de PowerShell o guárdelo como un script.

Para acceder a la ubicación de almacenamiento del archivo de registro de seguridad, debe ejecutar el código como administrador.

#Presentar registros de aplicación, seguridad y sistema en un array.
 $arrLogs = @(
     "Application"
     "Security"
     "System"
 )
 #Utilizar el cmdlet ForEach-Object para apuntar a cada registro respectivo con el cmdlet Get-ItemProperty.
 $arrLogs | ForEach-Object {
     #Utilizar el cmdlet Get-ItemProperty para listar la ruta de archivo configurada para el registro de aplicación, seguridad y sistema.
     Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\$_ -Name File | Select-Object PSChildName,File
 }

La siguiente captura de pantalla muestra la salida esperada del código, mostrando el nombre del registro y la ubicación de almacenamiento para los registros de Application, Security y System.

Application, Security, and System audit log location

Políticas de Auditoría: Definición de Eventos a Registrar

Por defecto, Windows no captura todo de los eventos de seguridad que podrían ser necesarios para detectar o investigar una violación. Para controlar qué registra y qué no registra Windows, debes definir y aplicar políticas de auditoría. Una política de auditoría es un conjunto de instrucciones enviadas a Windows que le indica qué eventos debe registrar.

Existen varias formas de asignar y trabajar con políticas de auditoría, como el uso de Directiva de Grupo. Directiva de Grupo funciona bien si debes implementar políticas de auditoría en muchas máquinas. Pero en este artículo, te centrarás en un solo dispositivo, por lo que usarás la herramienta auditpol. La herramienta auditpol viene instalada con Windows y te permite encontrar y establecer políticas de auditoría en un sistema Windows.

Buscar políticas de auditoría

Por ejemplo, para conocer el estado de todas las políticas de auditoría en tu sistema Windows, utiliza el parámetro /get como se muestra a continuación. El uso del parámetro /category seguido de un comodín le indica a auditpol que busque el estado de todas las políticas de auditoría, no solo una que coincida con una categoría o subcategoría específica.

#Obtener la configuración de la política de auditoría del sistema.
auditpol /get /category:*

La siguiente captura de pantalla muestra una versión truncada de la salida esperada del código, mostrando la categoría de política de auditoría de Administración de cuentas, subcategorías y estado (Configuración).

Audit policy category, subcategory, and configuration

A Setting that is configured as No Auditing means that all events associated with that audit policy subcategory will not be logged.

Configuración de políticas de auditoría

La herramienta auditpol puede hacer más que ver configuraciones de políticas de auditoría. También puede modificarlas utilizando el comando auditpol /set. Para demostrar futuras secciones en este tutorial, abre una consola de PowerShell como administrador y ejecuta el siguiente comando. Este comando comienza a registrar todos los eventos (éxito y fracaso) que son parte de la subcategoría de Inicio de sesión.

Configurar la subcategoría de Inicio de sesión obliga a tu sistema a registrar eventos:

#Establecer eventos de inicio de sesión para capturar actividad de éxito/fallo.
auditpol /set /subcategory:"Logon" /success:enable /failure:enable

Hay numerosos recursos disponibles para ayudarlo con la configuración de políticas de auditoría de mejores prácticas, incluidos los Estándares de Seguridad del Centro para Internet (CIS), y Guías de Implementación Técnica de Seguridad de la Agencia de Sistemas de Información de Defensa (DISA), y orientación publicada por Microsoft.

Generando registros de fallos de inicio de sesión para análisis

Este artículo será un tutorial y esperará que siga. Si ha configurado Windows para auditar eventos de inicio de sesión anteriormente, ahora generemos algunos eventos de seguridad para su análisis posterior. Más específicamente, generemos 35 intentos fallidos de inicio de sesión que se registrarán en el registro de seguridad de su sistema para simular actividad de fuerza bruta.

1. Abra su editor de código favorito.

2. Copia el siguiente código y pégalo en el editor de código. Este fragmento de código intenta abrir el proceso PowerShell.exe utilizando el cmdlet Start-Process con nombres de usuario y contraseñas ficticias.

#Define 5 nombres de usuario para registrar como intentos de inicio de sesión fallidos.
 $arrUsers = @(
     "AtaBlogUser1"
     "AtaBlogUser2"
     "AtaBlogUser3"
     "AtaBlogUser4"
     "AtaBlogUser5"
 )
 #Recorre los nombres de usuario utilizando ForEach-Object para generar un inicio de sesión fallido para cada uno.
 $arrUsers | ForEach-Object {
     $securePassword = ConvertTo-SecureString "AtA810GRu13Z%%" -AsPlainText -Force 
     $storedCredential = New-Object System.Management.Automation.PSCredential($_, $securePassword)
     Start-Process -FilePath PowerShell -Credential $storedCredential
 }
 #Genera 30 intentos de inicio de sesión fallidos para el usuario AtaBlogUser.
 $i = 0
 Do {
     $securePassword = ConvertTo-SecureString "AtA810GRu13Z%%" -AsPlainText -Force 
     $storedCredential = New-Object System.Management.Automation.PSCredential("AtaBlogUser", $securePassword)
     Start-Process -FilePath PowerShell -Credential $storedCredential
     $i++
 } Until ($i -eq 30)

3. Guarda el script de PowerShell como Invoke-BogusEvents.ps1 o cualquier otro nombre que desees y ejecuta el script.

Cuando se ejecute, notarás un error esperado repetido 35 veces que indica El nombre de usuario o la contraseña son incorrectos.

Authentication failure due to incorrect user name or password.

Si no estás recibiendo la salida esperada, asegúrate de que el servicio de Inicio de sesión secundario esté en estado Ejecutando.

Accediendo a los eventos de Windows con PowerShell

Ahora que estás seguro de tener al menos 35 eventos de seguridad de Windows, veamos cómo encontrarlos con el cmdlet Get-WinEvent de PowerShell.

Tal vez estés familiarizado con el cmdlet Get-EventLog de PowerShell, que también se utiliza para acceder al registro de eventos de forma programática. Get-EventLog utiliza una interfaz de programación de aplicaciones (API) de Win32 que está obsoleta y no se discutirá en esta publicación.

Abre una consola de PowerShell como administrador e invoca el cmdlet Get-WinEvent pasándole los parámetros FilterHashtable y MaxEvents como se muestra a continuación.

El siguiente comando consulta el registro de seguridad del sistema (LogName='Security') en busca del evento ID 4625 (ID=4625) y devuelve las primeras 10 instancias más recientes (MaxEvents 10).

# Filtra el registro de seguridad para las primeras 10 instancias del Evento ID 4625
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 10

Si tienes éxito, deberías ver una salida similar a la siguiente:

10 instances of Event ID 4625

Accediendo a las propiedades del evento con Get-WinEvent

En la sección anterior, utilizaste Get-WinEvent para ver eventos de seguridad de Windows de manera general, pero un evento de Windows contiene mucha más información. Cada evento de Windows tiene propiedades valiosas que puedes usar para un análisis más profundo.

Eventos de Windows en formato XML

Cuando Windows registra un evento, se almacena en formato XML. Si ese es el caso, ¿por qué tu comando Get-WinEvent devuelve objetos típicos de PowerShell? El cmdlet Get-WinEvent lee la API nativa de Windows y traduce los eventos en objetos de PowerShell para aumentar la funcionalidad.

Cada evento de Windows tiene varios atributos que siguen un esquema XML o estructura específica.

Verás a continuación que cada evento sigue una estructura específica con tres atributos:

  • nombre – El nombre de la propiedad
  • inType – La definición del tipo de entrada o cómo el evento acepta un valor
  • outputType – La definición del tipo de salida o cómo se registra el evento

Encontrar plantillas XML de eventos con PowerShell

Como se mencionó anteriormente, cada evento de seguridad de Windows se almacena en XML y tiene un esquema específico, pero ¿cómo se ve ese esquema? Vamos a descubrirlo.

En una de las secciones anteriores, generaste algunos eventos con ID 4625 en el registro de eventos de seguridad. Este tipo de evento tiene atributos específicos que solo se aplican a él. Para encontrar esos atributos y cómo es la plantilla:

1. Abre una consola de PowerShell como administrador si aún no la tienes abierta.

2. Ejecuta Get-WinEvent nuevamente, pero esta vez usa el parámetro ListProvider especificando el proveedor que Windows usa para registrar eventos en el registro de eventos de seguridad y solo devuelve la propiedad Events.

La propiedad Events contiene todos los eventos que el proveedor de la lista ha registrado y expone la plantilla XML para cada uno de esos eventos.

(Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events
Get Win Event List Provider

3. Ahora que tienes el código para encontrar plantillas de todos los tipos de evento, reduce eso mostrando solo el evento asociado con el ID 4625.

(Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events | Where-Object -Property ID -eq 4625

4. Una vez que estés devolviendo solo el tipo de evento de inicio de sesión con el ID de evento 4625, limítalo para mostrar solo la propiedad Template como se muestra a continuación.

# Obtener la plantilla XML del evento para las propiedades del evento con ID 4625.
 ((Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events | Where-Object -Property ID -eq 4625).Template

La siguiente captura de pantalla muestra una versión truncada de la salida del código, identificando el nombre de la propiedad del evento, el tipo de entrada y el tipo de salida. Puedes ver que el evento ID 4625 tiene propiedades de evento con diversas definiciones de entrada y salida.

La captura de pantalla a continuación resalta la propiedad SubjectUserSid del Evento ID 4625. Este evento en particular acepta un tipo de entrada (inType) de win:SID y muestra la salida (outType) como una string, que es cómo se almacena dentro del registro de seguridad.

XML template example

Cómo PowerShell traduce XML a objetos

Ahora que has visto cómo Windows almacena eventos en XML y cómo ver esas plantillas en PowerShell, veamos cómo PowerShell traduce ese XML en objetos.

1. Ejecuta el comando Get-WinEvent nuevamente para devolver nuestro evento ID 4625. Hasta ahora, esto no es nada nuevo. Observa que PowerShell solo muestra cuatro propiedades: TimeCreated, Id, LevelDisplayName y Message.

Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1
Get-WinEvent FilterHashtable

Por defecto, el cmdlet Get-WinEvent no devuelve todos los atributos de la fuente de datos XML del evento como un objeto PowerShell.

2. Ahora, pasa la salida del comando anterior al cmdlet Select-Object y especifica el parámetro Property pasando un valor de * para mostrar todas las propiedades.

Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1 | Select-Object -Property *

Observa que PowerShell estaba ocultando muchas propiedades diferentes. Más específicamente, una propiedad llamada Properties. La propiedad Properties contiene el valor de cada atributo del evento que viste anteriormente en la plantilla XML.

Powershell hiding Properties

3. Limita la salida del comando Get-WinEvent anterior para exponer la propiedad Properties. Esta propiedad almacena todas las propiedades del evento, no las propiedades del objeto PowerShell, en un array.

# Salida del array de propiedades del evento para la primera instancia del ID de evento 4625
 $eventProperties = (Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1).properties
 $eventProperties

En la izquierda de la captura de pantalla a continuación se encuentra la salida del comando anterior. El array contiene los valores para cada uno de los atributos XML en la plantilla XML en el lado derecho de la captura de pantalla.

La salida del código mostrada en la captura de pantalla indica que se produjo un fallo de autenticación para el usuario AtaBlogUser (TargetUserName) desde el sistema Desktop-XXXXX (WorkstationName) utilizando una dirección IP de ::1 (IpAddress).

Expected output correlating property values to Event ID 4625’s XML template.

Tal vez solo desees devolver el valor para la propiedad de evento TargetUserName. Dado que ya has almacenado todas las propiedades del evento en una variable llamada $eventProperties, haz referencia al quinto índice, que contiene el valor para TargetUserName.

Debes hacer referencia a la propiedad value en el objeto de propiedad de evento individual para devolver solo el valor (AtaBlogUser). $eventProperties[5].value

$eventProperties[5].value
Event attribute property positions

Las prácticas descritas a lo largo de esta sección se utilizarán en secciones posteriores para rastrear el intento de fuerza bruta que simulaste anteriormente en esta publicación.

Detección de un Ataque de Fuerza Bruta

¡Ahora estás preparado para usar tus habilidades de PowerShell para rastrear el ataque de fuerza bruta que replicaste anteriormente en esta publicación! Pongamos a prueba tus habilidades simulando cómo sería rastrear un ataque de fuerza bruta en base a un período de tiempo específico.

Supongamos que te alertaron sobre un incidente en el que tu organización cree que alguien está intentando iniciar sesión en un servidor Windows importante utilizando una cuenta administrativa. Esta actividad comenzó ayer. Debes descubrir la cantidad de eventos con el ID 4625: No se pudo iniciar sesión en una cuenta que ocurrieron en las últimas 24 horas y determinar el tipo de inicio de sesión de cada evento.

1. Encuentra todos los eventos con el ID 4625 (ID=4625) en el registro de seguridad de Windows (LogName="Security") de las últimas 24 horas (StartTime=((Get-Date).AddDays(-1).Date), hasta la hora actual (Get-Date).

$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1));EndTime=(Get-Date)}

2. Ahora, cuenta todos los eventos almacenados en la variable para determinar si hay más eventos de inicio de sesión fallidos de lo esperado.

$events.Count

Ahora deberías ver un valor numérico que indica la cantidad de veces que se encontró el evento con el ID 4625 en el registro de eventos de seguridad de las últimas 24 horas.

3. Ahora que has determinado que ocurrió un ataque de fuerza bruta, rastrea más información sobre estos eventos de seguridad de Windows. Para hacerlo, devuelve solo los atributos de cada uno de los eventos que te interesan.

Como se mencionó anteriormente, cada valor para un evento en particular se almacena en un array con un índice específico. Las propiedades interesantes del evento para esta demostración son las siguientes.

  • TargetUserName Índice: [5]
  • LogonType Índice: [10]
  • WorkstationName Índice: [13]
  • IpAddress Índice: [19]

El siguiente fragmento de código lee cada objeto en la variable $events, recopila solo las propiedades interesantes y las concatena en una sola línea.

#Extraer las propiedades del evento TargetUserName, LogonType, WorkstationName e IpAddress de todas las instancias del Event ID 4625 en las últimas 24 horas.
 $events | ForEach-Object {
     ## Hacer referencia a la propiedad del objeto properties
     ## Solo devolver el valor de los índices 5, 10, 13 y 19 del array properties
     ## Concatenar todos los valores juntándolos con una coma
     $_.properties[5,10,13,19].value -join ", "
 }

La siguiente captura de pantalla muestra una versión truncada de la salida esperada del código, detallando una lista separada por comas de TargetUserName, LogonType, WorkstationName e IpAddress.

A truncated version of the code’s output, detailing TargetUserName, LogonType, WorkstationName, and IpAddress property values.

Como viste en la plantilla XML anterior, el evento ID 4625 tiene un atributo LogonType. Este atributo indica el método en el que la cuenta intentó autenticarse. Después de investigar un poco más, notaste que el LogonType variaba en ocasiones.

LogonType attribute

El valor de LogonType es un valor numérico de 2 a 11, pero ¿qué significa cada uno? Realizas una investigación y descubres el significado de cada valor.

2 – Interactivo – Un usuario ha iniciado sesión en esta computadora.

3 – Red – Un usuario o computadora ha iniciado sesión en esta computadora desde la red.

4 – Lote – El tipo de inicio de sesión por lotes se utiliza en servidores por lotes, donde los procesos pueden ejecutarse en nombre de un usuario sin su intervención directa.

5 – Servicio – Un servicio fue iniciado por el Administrador de control de servicios.

7 – Desbloquear – Esta estación de trabajo fue desbloqueada.

8 – RedCleartext – Un usuario ha iniciado sesión en esta computadora desde la red. La contraseña del usuario se transmitió al paquete de autenticación en su forma no hash. Todos los paquetes de autenticación integrados hash credenciales antes de enviarlas a través de la red. Las credenciales no se transmiten en texto sin formato por la red (también llamado texto claro).

9 – NuevasCredenciales – Un llamador clonó su token actual y especificó nuevas credenciales para conexiones salientes. La nueva sesión de inicio de sesión tiene la misma identidad local, pero usa credenciales diferentes para otras conexiones de red.

10 – RemotoInteractivo – Un llamador clonó su token actual y especificó nuevas credenciales para conexiones salientes. La nueva sesión de inicio de sesión tiene la misma identidad local, pero usa credenciales diferentes para otras conexiones de red.

11 – Interactivo en caché – Un usuario ha iniciado sesión en esta computadora con credenciales de red que se almacenaron localmente en la computadora. El controlador de dominio no se contactó para verificar las credenciales.

Ahora que tienes una buena comprensión de cada LogonType, en lugar de ver un valor numérico en la salida, deseas una cadena más descriptiva. Para crear “mapas” en PowerShell, utiliza una hashtable.

$logonTypes = @{
     [uint32]2 = "Interactive"
     [uint32]3 = "Network"
     [uint32]4 = "Batch"
     [uint32]5 = "Service"
     [uint32]7 = "Unlock"
     [uint32]8 = "NetworkCleartext"
     [uint32]9 = "NewCredentials"
     [uint32]10 = "RemoteInteractive"
     [uint32]11 = "CachedInteractive"
 }

5. Combina Get-WinEvent y la hashtable de LogonType con ForEach-Object para crear un script que solo devuelva las propiedades que deseas con un valor de LogonType fácil de entender, como se muestra a continuación. El cmdlet Format-Table mejora la salida amigable para el usuario al formatear la respuesta de PowerShell como una tabla.

#Usa Get-WinEvent para acceder a las propiedades de cada instancia registrada del Evento ID 4625
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## Crea el valor numérico para el "mapa"
$logonTypes = @{
    [uint32]2 = "Interactive"
    [uint32]3 = "Network"
    [uint32]4 = "Batch"
    [uint32]5 = "Service"
    [uint32]7 = "Unlock"
    [uint32]8 = "NetworkCleartext"
    [uint32]9 = "NewCredentials"
    [uint32]10 = "RemoteInteractive"
    [uint32]11 = "CachedInteractive"
}
## Comienza a procesar cada objeto en el array $events
$events | ForEach-Object {
    ## Busca el valor numérico en la hashtable
    $logonType = $logonTypes[$_.properties[10].value] 
    #Crea un objeto personalizado de PowerShell para mostrar las propiedades relevantes del evento
    [PSCustomObject]@{     
        TimeCreated = $_.TimeCreated     
        TargetUserName = $_.properties[5].value     
        LogonType = $logonType     
        WorkstationName = $_.properties[13].value     
        IpAddress = $_.properties[19].value 
    }
} | Format-Table -Wrap

En este punto, ahora tienes un script que devuelve objetos de tipo PSCustomObject, ¡permitiéndote realizar muchos tipos diferentes de análisis! Para finalizar el análisis de este tutorial, prioriza los intentos de fallo de autenticación por TargetUserName. Para priorizar los fallos por la propiedad TargetUserName, combina el código anterior con el cmdlet Group-Object. Utiliza Sort-Object y su interruptor Descending para identificar al usuario que más está causando problemas.

#Use Get-WinEvent para acceder a las propiedades de cada instancia registrada del Evento ID 4625
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## Crea el valor numérico para convertirlo en cadena "map"
$logonTypes = @{
    [uint32]2 = "Interactive"
    [uint32]3 = "Network"
    [uint32]4 = "Batch"
    [uint32]5 = "Service"
    [uint32]7 = "Unlock"
    [uint32]8 = "NetworkCleartext"
    [uint32]9 = "NewCredentials"
    [uint32]10 = "RemoteInteractive"
    [uint32]11 = "CachedInteractive"
}
## Comienza a procesar cada objeto en la matriz $events
$events | ForEach-Object {
    ## Busca el valor numérico en la tabla hash
    $logonType = $logonTypes[$_.properties[10].value] 
    #Crea un objeto personalizado de PowerShell para mostrar las propiedades relevantes del evento 
    [PSCustomObject]@{     
        TimeCreated = $_.TimeCreated     
        TargetUserName = $_.properties[5].value     
        LogonType = $logonType     
        WorkstationName = $_.properties[13].value     
        IpAddress = $_.properties[19].value 
    }
} | Group-Object -Property TargetUserName | Sort-Object -Property Count -Descending

¡Excelente trabajo! Acabas de usar PowerShell para detectar el intento de fuerza bruta que simulaste anteriormente en esta publicación. ¡Según la salida, AtaBlogUser falló en autenticarse 30 veces en las últimas 24 horas!

AtaBlogUser Logon Failures

Siguientes Pasos

En este tutorial, aprendiste cómo Windows registra eventos, cómo habilitar el registro de eventos para ciertos tipos de eventos, y cómo construir una herramienta de PowerShell para consultar estos eventos.

Con el script de PowerShell que tienes ahora, ¿cómo puedes mejorarlo? ¿Cómo usarás el código que has aprendido hoy para construir una herramienta mejor?

Source:
https://adamtheautomator.com/windows-security-events/