Seguimiento y registro de scriptsScript Tracing and Logging

Mientras que Windows PowerShell ya tiene la opción de Directiva de grupo LogPipelineExecutionDetails para registrar la invocación de cmdlets, el lenguaje de scripting de PowerShell tiene muchas características que quizás quiera registrar y/o auditar.While Windows PowerShell already has the LogPipelineExecutionDetails Group Policy setting to log the invocation of cmdlets, PowerShell’s scripting language has plenty of features that you might want to log and/or audit. La nueva característica de seguimiento detallado de scripts permite habilitar el seguimiento detallado y el análisis del uso de scripting de Windows PowerShell en un sistema.The new Detailed Script Tracing feature lets you enable detailed tracking and analysis of Windows PowerShell scripting use on a system. Después de habilitar el seguimiento detallado de scripts, Windows PowerShell registra todos los bloques de script en el registro de eventos ETW, Microsoft-Windows-PowerShell/Operational.After you enable detailed script tracing, Windows PowerShell logs all script blocks to the ETW event log, Microsoft-Windows-PowerShell/Operational. Si un bloque de script crea otro bloque de script (por ejemplo, un script que llame al cmdlet Invoke-Expression en una cadena), también se registra este bloque de script resultante.If a script block creates another script block (for example, a script that calls the Invoke-Expression cmdlet on a string), that resulting script block is logged as well.

El registro de estos eventos se puede habilitar a través de la opción de Directiva de grupo Activar el registro de bloque de script de PowerShell (en Plantillas administrativas -> Componentes de Windows -> Windows PowerShell).Logging of these events can be enabled through the Turn on PowerShell Script Block Logging Group Policy setting (in Administrative Templates -> Windows Components -> Windows PowerShell).

Los eventos son:The events are:

CanalChannel OperativoOperational
NivelLevel VerboseVerbose
Código de operaciónOpcode CrearCreate
TareaTask CommandStartCommandStart
Palabra claveKeyword Espacio de ejecuciónRunspace
Id. de eventoEventId Engine_ScriptBlockCompiled (0x1008 = 4104)Engine_ScriptBlockCompiled (0x1008 = 4104)
MensajeMessage Creando texto de bloque de script (%1 de %2):Creating Scriptblock text (%1 of %2):
%3%3
Id. de bloque de script: %4ScriptBlock ID: %4

El texto insertado en el mensaje es la extensión del bloque de script compilado.The text embedded in the message is the extent of the script block compiled. El identificador es un GUID que se conserva durante la vida del bloque de script.The ID is a GUID that is retained for the life of the script block.

Cuando se habilita el registro detallado, la característica escribe los marcadores de inicio y fin:When you enable verbose logging, the feature writes begin and end markers:

CanalChannel OperativoOperational
NivelLevel VerboseVerbose
Código de operaciónOpcode Abrir (/Cerrar)Open (/ Close)
TareaTask CommandStart (/ CommandStop)CommandStart (/ CommandStop)
Palabra claveKeyword Espacio de ejecuciónRunspace
Id. de eventoEventId ScriptBlock_Invoke_Start_Detail (0x1009 = 4105) /ScriptBlock_Invoke_Start_Detail (0x1009 = 4105) /
ScriptBlock_Invoke_Complete_Detail (0x100A = 4106)ScriptBlock_Invoke_Complete_Detail (0x100A = 4106)
MensajeMessage Invocación iniciada (/completada) del id. de bloque de script: %1Started (/ Completed) invocation of ScriptBlock ID: %1
Id. de espacio de ejecución: %2Runspace ID: %2

El identificador es el GUID que representa el bloque de script (que puede estar correlacionado con Id. de evento 0x1008) y el identificador de espacio de ejecución representa el espacio de ejecución en el que se ejecutó este bloque de script.The ID is the GUID representing the script block (that can be correlated with event ID 0x1008), and the Runspace ID represents the runspace in which this script block was run.

Los signos de porcentaje del mensaje de invocación representan las propiedades de ETW estructuradas.Percent signs in the invocation message represent structured ETW properties. Mientras se reemplazan por los valores reales en el texto del mensaje, una manera más segura de acceder a ellos es recuperar el mensaje con el cmdlet Get-WinEvent y, luego, usara la matriz Properties del mensaje.While they are replaced with the actual values in the message text, a more robust way to access them is to retrieve the message with the Get-WinEvent cmdlet, and then use the Properties array of the message.

Este es un ejemplo de cómo esta funcionalidad puede ayudarle a descubrir un intento malicioso para cifrar y ofuscar un script:Here's an example of how this functionality can help unwrap a malicious attempt to encrypt and obfuscate a script:

## Malware
function SuperDecrypt
{
    param($script)
    $bytes = [Convert]::FromBase64String($script)

    ## XOR “encryption”
    $xorKey = 0x42
    for($counter = 0; $counter -lt $bytes.Length; $counter++)
    {
        $bytes[$counter] = $bytes[$counter] -bxor $xorKey
    }
    [System.Text.Encoding]::Unicode.GetString($bytes)
}

$decrypted = SuperDecrypt "FUIwQitCNkInQm9CCkItQjFCNkJiQmVCEkI1QixCJkJlQg=="
Invoke-Expression $decrypted

Si se ejecuta, generará las entradas de registro siguientes:Running this generates the following log entries:

Compiling Scriptblock text (1 of 1):
function SuperDecrypt
{
    param($script)
    $bytes = [Convert]::FromBase64String($script)
    ## XOR "encryption"
    $xorKey = 0x42
    for($counter = 0; $counter -lt $bytes.Length; $counter++)
    {
        $bytes[$counter] = $bytes[$counter] -bxor $xorKey
    }
    [System.Text.Encoding]::Unicode.GetString($bytes)

}
ScriptBlock ID: ad8ae740-1f33-42aa-8dfc-1314411877e3

Compiling Scriptblock text (1 of 1):
$decrypted = SuperDecrypt "FUIwQitCNkInQm9CCkItQjFCNkJiQmVCEkI1QixCJkJlQg=="
ScriptBlock ID: ba11c155-d34c-4004-88e3-6502ecb50f52

Compiling Scriptblock text (1 of 1):
Invoke-Expression $decrypted
ScriptBlock ID: 856c01ca-85d7-4989-b47f-e6a09ee4eeb3

Compiling Scriptblock text (1 of 1):
Write-Host 'Pwnd'
ScriptBlock ID: 5e618414-4e77-48e3-8f65-9a863f54b4c8

Si la longitud del bloque de script supera la que ETW es capaz de contener en un único evento, Windows PowerShell divide el script en varias partes. A continuación, se muestra código de ejemplo para volver a combinar un script a partir de sus mensajes de registro:Here is sample code to recombine a script from its log messages:

$created = Get-WinEvent -FilterHashtable @{ ProviderName="Microsoft-Windows-PowerShell"; Id = 4104 } | Where-Object { $_.<...> }
$sortedScripts = $created | sort { $_.Properties[0].Value }
$mergedScript = -join ($sortedScripts | % { $_.Properties[2].Value })

Al igual que con todos los sistemas de registro que tienen un búfer de retención limitado (es decir, registros de ETW), un ataque contra esta infraestructura es inundar el registro de eventos falsos para ocultar las pruebas anteriores.As with all logging systems that have a limited retention buffer (i.e. ETW logs), one attack against this infrastructure is to flood the log with spurious events to hide earlier evidence. Para protegerse de este ataque, asegúrese de que tiene algún tipo de colección de registro de eventos configurado (es decir, Colección de reenvío de eventos de Windows, Spotting the Adversary with Windows Event Log Monitoring) para desplazar los registros de eventos del equipo tan pronto como sea posible.To protect yourself from this attack, ensure that you have some form of event log collection set up (i.e., Windows Event Forwarding, Spotting the Adversary with Windows Event Log Monitoring) to move event logs off of the computer as soon as possible.