
Powershell ist ein fester Bestandteil moderner Windows-Systeme und bietet durch .NET-Anbindung mächtige Möglichkeiten zur Automatisierung. Diese Eigenschaften machen es auch für Angreifer attraktiv:
Angreifer codieren PowerShell-Befehle um Sicherheitsmechanismen zu umgehen:
Invoke-Expression, Net.WebClient, DownloadString oder Namen bekannter Schadsoftware wie Mimikatz.IEX (New-Object Net.WebClient).DownloadString(...)), ohne dass eine Datei auf die Festplatte geschrieben wird. Dies erschwert die forensische Analyse und die Erkennung erheblich.-Command oder -EncodedCommand kann die Powershell Execution Policy umgehen, die standardmäßig das Ausführen von Skripten einschränken soll.Laut Microsoft-Dokumentation ist der Hauptzweck von `-EncodedCommand`, die Ausführung von Befehlen zu ermöglichen, die komplexe Anführungszeichen, geschweifte Klammern oder andere Sonderzeichen enthalten, die bei der direkten Übergabe an die Kommandozeile zu Problemen führen könnten. Durch die Kodierung des Befehls als Base64-String werden diese Interpretationsprobleme vermieden. Außerdem sind wir in Kundenumgebungen bereits auf die folgenden Verwendungen gestoßen:
[Convert]::FromBase64String innerhalb des Skripts, nicht den -EncodedCommand Parameter beim Aufruf.-EncodedCommand ParameterDer Parameter -EncodedCommand ist ein legitimes Feature von powershell.exe (Windows Powershell 5.1 und früher) und pwsh.exe (Powershell 6 und neuer). Powershell erlaubt es, Parameter in vollständig ausgeschriebener Form (z. B. -EncodedCommand) oder in verkürzter Schreibweise (wie -enc oder sogar -e) zu verwenden, solange die Kurzform eindeutig auf einen gültigen Parameter verweist. Dieses Verhalten basiert auf einem eingebauten Mechanismus zur automatischen Parametervervollständigung, der dem Nutzer Arbeit abnehmen und Fehler reduzieren soll. Um codierte Powershell-Befehle zu finden, reicht es also nicht nach dem Parameter -EncodedCommand zu suchen. Die alternativen Schreibweisen müssen in der Suche berücksichtigt werden.
# Der ursprüngliche Befehl
$command = "ping 8.8.8.8"
# 1. String in Bytes umwandeln (unter Verwendung von UTF-16LE)
$bytesUtf16le = [System.Text.Encoding]::Unicode.GetBytes($command)
# 2. Bytes in einen Base64-String umwandeln
$base64CommandUtf16le = [System.Convert]::ToBase64String($bytesUtf16le)
# Ausgabe
Write-Host "Ursprünglicher Befehl: $command"
Write-Host "Bytes (UTF-16LE) als Hex-String: $($bytesUtf16le | ForEach-Object { $_.ToString('X2') })"
Write-Host "Base64-kodierter Befehl (aus UTF-16LE Bytes): $base64CommandUtf16le"powershell.exe -EncodedCommand $encodedCommand//Get Powershell and pwsh events
#event_simpleName=ProcessRollup2
| event_platform=Win
| ImageFileName=/\\(powershell|pwsh)\.exe/i
//Search for "-EncodeCommand" and variations
| groupby([ParentBaseFileName, CommandLine], function=stats([count(aid, distinct=true, as="uniqueEndpointCount"), count(aid, as="executionCount")]), limit=max)
//Set endpoint prevalence threshold
| uniqueEndpointCount < 3
//Calculating command length & Isolate Base64 sting
| cmdLength := length("CommandLine")
//| CommandLine=/\s(|[\^])-(|[\^])[e]{1,2}[ncodema^]*\s(?<base64String>\S+)|^/i
//| CommandLine=/\s-[eE^]{1,2}[ncodema^]*\s(?<base64String>\S+)/i
| CommandLine=/\s(|[\^])-(|[\^])[e]{1,2}[ncodema^]*\s(?<base64String>\S+)/i
//| replace("^", with="", field=base64String, as=CleanBase64String)
//Get Entropy of Base64 String
| b64Entropy := shannonEntropy("base64String")
// Set entropy threshold
| b64Entropy > ?EntropyGreaterThan
//Decode encoded command blob
| decodedCommand := base64Decode(base64String, charset="UTF-16LE")
//Outputting to table
| table([ParentBaseFileName, uniqueEndpointCount, executionCount, cmdLength, b64Entropy, decodedCommand, CommandLine])
//Uncomment next line to search URLs in the decoded command
//| decodedCommand=/https?/i
//Uncomment next line to search IP:Port in the decoded command
//|regex("(?<ip>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\:(?<port>\d{2,5})", field=decodedCommand)
//Uncomment next line to search IP in the decoded command
//|regex("(?<ip>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})", field=decodedCommand)Vom Exploit bis zur Defense: Echte Security-Insights aus unserem SOC und Research-Lab