Ablaufverfolgung und Protokollierung von SkriptsScript Tracing and Logging

Während PowerShell bereits über die Gruppenrichtlinieneinstellung LogPipelineExecutionDetails verfügt, um den Aufruf von Cmdlets zu protokollieren, bietet die PowerShell-Skriptsprache mehrere Features, die Sie ggf. protokollieren und überwachen möchten.While PowerShell already has the LogPipelineExecutionDetails Group Policy setting to log the invocation of cmdlets, PowerShell's scripting language has several features that you might want to log and audit. Das neue Feature zur detaillierten Ablaufverfolgung von Skripts stellt eine detaillierte Nachverfolgung und Analyse der Verwendung von PowerShell-Skriptaktivitäten auf einem System bereit.The new Detailed Script Tracing feature provides detailed tracking and analysis of PowerShell script activity on a system. Nachdem Sie die detaillierte Ablaufverfolgung von Skripts aktiviert haben, protokolliert PowerShell alle Skriptblöcke im ETW-Ereignisprotokoll Microsoft-Windows-PowerShell/Operational.After enabling detailed script tracing, PowerShell logs all script blocks to the ETW event log, Microsoft-Windows-PowerShell/Operational. Wenn ein Skriptblock einen anderen Skriptblock erzeugt, z. B. durch Aufrufen von Invoke-Expression, wird der aufgerufene Skriptblock ebenfalls protokolliert.If a script block creates another script block, for example, by calling Invoke-Expression, the invoked script block also logged.

Die Protokollierung wird über die Gruppenrichtlinieneinstellung Protokollierung von PowerShell-Skriptblöcken aktivieren (Administrative Vorlagen -> Windows-Komponenten -> Windows PowerShell) aktiviert.Logging is enabled through the Turn on PowerShell Script Block Logging Group Policy setting in Administrative Templates -> Windows Components -> Windows PowerShell.

Die Ereignisse sind wie folgt:The events are:

KanalChannel BetriebsbereitOperational
EbeneLevel AusführlichVerbose
OpcodeOpcode ErstellenCreate
AufgabeTask CommandStartCommandStart
SchlüsselwortKeyword RunspaceRunspace
Ereignis-IDEventId Engine_ScriptBlockCompiled (0x1008 = 4104)Engine_ScriptBlockCompiled (0x1008 = 4104)
MeldungMessage Skriptblocktext (%1 von %2) wird erstellt:Creating Scriptblock text (%1 of %2):
%3%3
ScriptBlock-ID: %4ScriptBlock ID: %4

Der in der Meldung eingebettete Text gibt das Ausmaß des kompilierten Skriptblocks an.The text embedded in the message is the extent of the script block compiled. Die ID ist eine GUID, die für die Gültigkeitsdauer des Skriptblocks beibehalten wird.The ID is a GUID that is retained for the life of the script block.

Wenn Sie die ausführlichen Protokollierung aktivieren, schreibt das Feature die Markierungen „begin“ und „end“:When you enable verbose logging, the feature writes begin and end markers:

KanalChannel BetriebsbereitOperational
EbeneLevel AusführlichVerbose
OpcodeOpcode Öffnen/SchließenOpen / Close
AufgabeTask CommandStart/CommandStopCommandStart / CommandStop
SchlüsselwortKeyword RunspaceRunspace
Ereignis-IDEventId ScriptBlock_Invoke_Start_Detail (0x1009 = 4105) /ScriptBlock_Invoke_Start_Detail (0x1009 = 4105) /
ScriptBlock_Invoke_Complete_Detail (0x100A = 4106) /ScriptBlock_Invoke_Complete_Detail (0x100A = 4106)
MessageMessage Der Aufruf der ScriptBlock-ID wurde gestartet/abgeschlossen: %1Started / Completed invocation of ScriptBlock ID: %1
Runspace-ID: %2Runspace ID: %2

Die ID ist die GUID, die den Skriptblock darstellt (der mit der Ereignis-ID 0x1008 korreliert werden kann). Die Runspace-ID stellt den Runspace dar, in dem dieser Skriptblock ausgeführt wurde.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.

Prozentzeichen in der Aufrufmeldung stellen strukturierte ETW-Eigenschaften dar.Percent signs in the invocation message represent structured ETW properties. Wenngleich sie im Meldungstext durch die tatsächlichen Werte ersetzt werden, empfiehlt sich für den Zugriff darauf eher das Abrufen der Meldung mit dem Cmdlet „Get-WinEvent“ und dann das Untersuchen des Bereichs Eigenschaften der Meldung.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.

Hier ist ein Beispiel, wie diese Funktionalität helfen kann, einen böswilligen Versuch zum Verschlüsseln und Verschleiern eines Skripts zu erkennen: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

Bei Ausführen dieses Befehls werden die folgenden Einträge generiert: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

Wenn die Länge eines Skriptblocks größer als die Kapazität eines einzelnen Ereignisses ist, teilt PowerShell das Skript in mehrere Teile auf. Hier ist Beispielcode für das erneute Zusammenzusetzen der Protokollmeldungen eines Skripts: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 })

Wie alle Protokollierungssysteme, die einen begrenzten Aufbewahrungspuffer haben, besteht eine Angriffsmöglichkeit auf diese Infrastruktur darin, dass Protokoll mit gefälschten Ereignissen zu überfluten, um ein früheres Vorkommen zu vertuschen.As with all logging systems that have a limited retention buffer, one way to attack this infrastructure is to flood the log with spurious events to hide earlier evidence. Um sich vor diesen Angriffen zu schützen, stellen Sie sicher, dass Sie eine Form der Ereignisprotokollerfassung eingerichtet haben, z. B. Windows-Ereignisweiterleitung.To protect yourself from this attack, ensure that you have some form of event log collection set up Windows Event Forwarding. Weitere Informationen finden Sie unter Ermitteln des Angreifers mit Überwachung des Windows-Ereignisprotokolls.For more information, see Spotting the Adversary with Windows Event Log Monitoring.