Pide tu presupuesto ya!
12th June 2024
Al trabajar con registros de eventos de Windows, especialmente el registro de seguridad, puede haber casos en los que necesite extraer información específica de los eventos.
Pero descubrirás que no es tan fácil como imaginas.
Recientemente, necesitaba consultar los eventos de Windows desde el registro de eventos de seguridad para conocer los eventos de inicio de sesión del usuario (ID de evento 4624 para ser específico). Pero no todo eventos, solo eventos que coinciden con una sintaxis de nombre de usuario específica de domain_name/username.
Únase a mí en un viaje por los registros de eventos de Windows, XML y XPath mientras analizamos los registros de eventos de Windows con PowerShell. Para demostrarlo, veamos un ejemplo.
Primero debe generar al menos un evento de Windows. Como estoy trabajando con eventos de inicio de sesión de usuarios, tomaré solo un evento como ejemplo con el ID de evento 4624.
$eventRecord = Get-WinEvent -MaxEvents 1 -FilterHashtable @{LogName="Security";ID=4624}
¡Hecho! Ahora tiene un objeto System.Diagnostics.Eventing.Reader.EventLogRecord.
Ahora, este tutorial sería bastante corto si solo necesitara filtrar propiedades básicas como Id o TimeCreated pero desafortunadamente, necesito filtrar información del campo Mensaje de un evento. Get-WinEvent no crea un objeto amigable para que podamos consultarlo. En lugar de eso, debes construir el tuyo propio.
Para hacerlo, primero debe convertir el registro a XML usando el ToXml() método.
El ToXml() El método convierte todo el objeto de evento en una cadena XML.
$xmlEventRecord = $eventRecord.ToXml()

A menos que seas sadomasoquista y prefieras usar expresiones regulares, necesitas tener esto en un formato estructurado para consultar elementos dentro de él. Por suerte para nosotros, puedes convertir fácilmente cadenas XML a tipos Xml.Document usando el [xml] tipo acelerador.
$xmlEventRecord = [xml]$eventRecord.ToXml()

El formato XML del evento contiene varios elementos y debemos navegar a través de ellos para encontrar TargetUserName y TargetDomainName. Usaremos consultas XPath para lograr esto.
💡 Los registros de eventos de Windows no son totalmente compatibles con XPath. Ellos utilizar un subconjunto de XML 1.0 eso está severamente limitado en las funciones que puede utilizar.
En cada XmlDocument objeto, tienes un SelectSingleNode() método que le permite pasar una consulta XPath para buscar elementos en el documento, pero primero debe generar la consulta XPath.
Al crear consultas XPath, primero debe determinar la “ruta” a la entidad que está consultando o al menos el nodo que contiene el valor que busca. En este caso, los elementos que buscamos están en EventEventData almacenado como un Data nodo con Name atributos con valores de TargetUserName y TargetDomainName que buscamos.
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Security-Auditing" Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/>
<EventID>4624</EventID>
<Version>2</Version>
<Level>0</Level>
<Task>12544</Task>
<Opcode>0</Opcode>
<Keywords>0x8020000000000000</Keywords>
<TimeCreated SystemTime="2024-06-07T17:23:16.5812423Z"/>
<EventRecordID>260494</EventRecordID>
<Correlation/>
<Execution ProcessID='768' ThreadID='1708'/>
<Channel>Security</Channel>
<Computer>ATA-Devo-SRV-01.atadevo.local</Computer>
<Security/>
</System>
<EventData>
<Data Name="SubjectUserSid">S-1-5-18</Data>
<Data Name="SubjectUserName">ATA-DEVO-SRV-01$</Data>
<Data Name="SubjectDomainName">ATADEVO</Data>
<Data Name="SubjectLogonId">0x3e7</Data>
<Data Name="TargetUserSid">S-1-5-21-3909178112-971454023-1868345993-500</Data>
<Data Name="TargetUserName">atadevoadmin</Data>
<Data Name="TargetDomainName">ATADEVO</Data>
<Data Name="TargetLogonId">0x546f80</Data>
<Data Name="LogonType">7</Data>
<Data Name="LogonProcessName">Negotiat</Data>
<Data Name="AuthenticationPackageName">Negotiate</Data>
<Data Name="WorkstationName">ATA-DEVO-SRV-01</Data>
<Data Name="LogonGuid"> { 97292dbd-b376-1168-64b5-b750cafa6348 }</Data>
<Data Name="TransmittedServices">-</Data>
<Data Name="LmPackageName">-</Data>
<Data Name="KeyLength">0</Data>
<Data Name="ProcessId">0x300</Data>
<Data Name="ProcessName">C:WindowsSystem32lsass.exe</Data>
<Data Name="IpAddress">-</Data>
<Data Name="IpPort">-</Data>
<Data Name="ImpersonationLevel">%%1833</Data>
<Data Name="RestrictedAdminMode">-</Data>
<Data Name="TargetOutboundUserName">-</Data>
<Data Name="TargetOutboundDomainName">-</Data>
<Data Name="VirtualAccount">%%1843</Data>
<Data Name="TargetLinkedLogonId">0x0</Data>
<Data Name="ElevatedToken">%%1842</Data>
</EventData>
</Event>
Si no trabaja con XPath con demasiada frecuencia, su primera opción probablemente sería hacer algo como esto:
$xmlEventRecord.SelectSingleNode("//Data[@Name="TargetUserName"]")
La consulta XPath es sólida. esta buscando todo Data nodos con un atributo de Name y un valor de TargetUserName. Pero no funcionará. ¿Por qué? Este XML utiliza un espacio de nombres.
xmlns="http://schemas.microsoft.com/win/2004/08/events/event
Los espacios de nombres XML se utilizan para proporcionar elementos y atributos con nombres únicos en un documento XML. Una instancia XML puede contener nombres de elementos o atributos de más de un vocabulario XML. Si a cada vocabulario se le asigna un espacio de nombres, se puede resolver la ambigüedad entre elementos o atributos con nombres idénticos.
Para consultar un documento XML que utiliza un espacio de nombres, primero debe definir un XmlNamespaceManager y luego agregarle ese espacio de nombres.
$eventNamespace = New-Object System.Xml.XmlNamespaceManager($xmlEventRecord.NameTable)
$eventNamespace.AddNamespace("evt", "http://schemas.microsoft.com/win/2004/08/events/event")
Una vez que haya definido el espacio de nombres, deberá utilizar ese espacio de nombres en el SelectSingleNode() consulta.
$xmlEventRecord.SelectSingleNode("//evt:Data[@Name="TargetUserName']", $eventNamespace)
En este punto, debería poder extraer el nodo XML.

El SelectSingleNode() El método no devolverá una cadena simple que necesitará. En cambio, devuelve un System.Xml.XmlElement objeto del cual necesitarás extraer el valor del nodo. Para hacer eso, puede usar su conocida notación de puntos de PowerShell para hacer referencia al InnerText propiedad.
$xmlEventRecord.SelectSingleNode("//evt:Data[@Name="TargetUserName"]", $eventNamespace).InnerText
Una vez que sepa cómo encontrar el valor del texto, volverá al territorio familiar de PowerShell. En este punto, sólo necesitas extraer ambas cadenas (TargetUserName y TargetDomainName) en este caso y concatenarlos juntos.
$targetUserName = $xmlEventRecord.SelectSingleNode("//evt:Data[@Name="TargetUserName"]", $eventNamespace).InnerText
$targetDomainName = $xmlEventRecord.SelectSingleNode("//evt:Data[@Name="TargetDomainName"]", $eventNamespace).InnerText
$domainUser = "$targetDomainName$targetUserName"
Finalmente, combine lo extraído TargetUserName y TargetDomainName para formar el formato DomainNameUsername.

¡Y tu estas listo!
Si está creando scripts de PowerShell que consultan registros de eventos de Windows, es probable que tenga que hacerlo, especialmente si desea consultar el Message campo.
Aquí está el script completo si desea copiarlo y pegarlo.
# Step 1: Query the Security log for Event ID 4624
$eventRecord = Get-WinEvent -MaxEvents 1 -FilterHashtable @{LogName="Security";ID=4624}
# Step 2: Convert the event record to XML
$xmlEventRecord = [xml]$eventRecord.ToXml()
# Step 3: Define the namespace manager
$eventNamespace = New-Object System.Xml.XmlNamespaceManager($xmlEventRecord.NameTable)
$eventNamespace.AddNamespace("evt", "<http://schemas.microsoft.com/win/2004/08/events/event>")
# Step 4: Extract TargetUserName and TargetDomainName using XPath
$targetUserName = $xmlEventRecord.SelectSingleNode("//evt:Data[@Name="TargetUserName"]", $eventNamespace).InnerText
$targetDomainName = $xmlEventRecord.SelectSingleNode("//evt:Data[@Name="TargetDomainName"]", $eventNamespace).InnerText
# Step 5: Combine DomainName and UserName
$domainUser = "$targetDomainName\$targetUserName"
$domainUser
Leave a comment