ADMIN
2024
01
2023-12-30T12:00:00
Infrastruktur- und Assetmanagement
PRAXIS
036
Sicherheit
PowerShell
Netzwerkmanagement
Fünf zentrale PowerShell-Security-Features
Automatisch sicher
von Philip Lorenz
Veröffentlicht in Ausgabe 01/2024 - PRAXIS
Mit den zahlreichen Möglichkeiten, die die PowerShell für Automatisierung und flexiblere Administration bietet, entsteht auch Potenzial für Missbrauch. Dies kann aufgrund unzureichender Restriktionen seitens eines Windows-Servers oder mangels Erfahrung des Admins beim Aufsetzen eines PowerShell-Skripts geschehen. Wir beleuchten daher fünf wesentliche Sicherheitsfallstricke und wie sich diese mit minimalem Aufwand umgehen lassen, um eine sichere Umgebung für PowerShell-Code zu implementieren.

Bei PowerShell-Neulingen führt die sogenannte Execution-Policy oft zu Verwirrung. Selbst erstellte Skripte, die auf dem eigenen System problemlos laufen, lassen sich nicht auf anderen Computern oder Servern starten. Dies liegt häufig an der festgelegten Execution-Policy, die auf Windows-Systemen bestimmt, welche Skripte auf einem System ausgeführt werden dürfen.
1. Übersicht der Execution-Policies
Mit dem Befehl Get-ExecutionPolicy
fragen Sie die aktuell festgelegte Richtlinie ab. Eine Modifikation ist dabei über Set-ExecutionPolicy <PolicyName> möglich. Es existieren verschiedene Policies, die jeweils unterschiedliche Bezeichnungen und Restriktionen aufweisen:
- Restricted: Kein Skript lässt sich ausführen, einschließlich solcher, die von PowerShell-Profilen geladen werden.
Bei PowerShell-Neulingen führt die sogenannte Execution-Policy oft zu Verwirrung. Selbst erstellte Skripte, die auf dem eigenen System problemlos laufen, lassen sich nicht auf anderen Computern oder Servern starten. Dies liegt häufig an der festgelegten Execution-Policy, die auf Windows-Systemen bestimmt, welche Skripte auf einem System ausgeführt werden dürfen.
1. Übersicht der Execution-Policies
Mit dem Befehl Get-ExecutionPolicy
fragen Sie die aktuell festgelegte Richtlinie ab. Eine Modifikation ist dabei über Set-ExecutionPolicy <PolicyName> möglich. Es existieren verschiedene Policies, die jeweils unterschiedliche Bezeichnungen und Restriktionen aufweisen:
- Restricted: Kein Skript lässt sich ausführen, einschließlich solcher, die von PowerShell-Profilen geladen werden.
- AllSigned: Nur Skripte, die von einem vertrauenswürdigen Herausgeber signiert sind, dürfen starten.
- RemoteSigned: Lokale Skripte sind ohne Signatur erlaubt, Code aus dem Internet muss eine Signatur von einem vertrauenswürdigen Herausgeber haben.
- Unrestricted: Alle Skripte sind erlaubt, solche aus dem Internet muss der Benutzer vor der Ausführung bestätigen.
- Bypass: Es gibt keine Einschränkungen; alle Skripte können ohne Warnungen oder Aufforderungen laufen.
- Undefined: Es ist keine Policy gesetzt. Das Verhalten ist das Gleiche wie bei Restricted auf Windows-Client-Systemen und RemoteSigned auf Windows Server, sofern keine Gruppenrichtlinien angewendet werden.
Die Best Practice empfiehlt, "AllSigned" zu verwenden, was ausschließlich das Ausführen von Skripten erlaubt, die von einer vertrauenswürdigen CA signiert sind. Dies bietet verschiedene Vorteile:
- Die Signatur dokumentiert den Autor eines Skripts und somit die Zuständigkeit.
- Skripte werden automatisch in "signiert" und "unsigniert" unterteilt, was zu einer Art "Staging" führt. Von einem signierten Skript kann eher angenommen werden, dass es funktionsfähig ist.
- Der Signierungsvorgang kann der Qualitätssicherung dienen, bei der der Zertifikatsgenehmiger bei mangelnder Codequalität eingreifen kann.
Die AllSigned-Richtlinie bietet also über die offensichtlichen Vorteile hinaus verschiedene Mehrwerte, die die Sicherheit positiv beeinflussen, wie die Steigerung der Code-Qualität und eine klare Definition von Zuständigkeiten.
Es ist jedoch wichtig zu betonen, dass eine bestehende Execution-Policy von böswilligen Angreifern umgangen werden kann. Selbst Microsoft stellt mittlerweile klar, dass die Execution-Policy weniger ein Sicherheitssystem zur Einschränkung von Benutzeraktionen ist, sondern vielmehr dazu dient, grundlegende Regeln festzulegen, um unbeabsichtigtes Verstoßen dagegen zu verhindern [1]. Diese Richtlinie ist also nur ein Teilaspekt eines umfassenden Sicherheitskonzepts.
Signieren von PowerShell-Skripts
Das Signieren von Skripten erhöht die Sicherheit, indem es deren Authentizität und Integrität gewährleistet. Somit lässt sich ein Skript nicht modifizieren, ohne dass es erneut den Signierungsprozess durchlaufen muss. Die weiteren Vorteile wurden bereits im vorangegangenen Abschnitt erläutert. Hier konzentrieren wir uns auf den eigentlichen Signierungsprozess und darauf, wie Sie diesen ebenfalls mittels PowerShell-Code darstellen. Dabei stehen Ihnen verschiedene Methoden offen: SelfSigned-Zertifikate, Code-Signing durch unternehmenseigene Certification Authority (CA) und Code-Signing durch eine öffentliche Certification Authority.
Führen Sie Skripte nur innerhalb der eigenen Organisation aus, reicht das Signieren durch eine interne CA vollkommen aus. Bei der Verwendung von Active Directory Domain Services (ADDS) erstellen Sie auf dem CA-Server zunächst eine neue Zertifikatvorlage für Code-Signing. Dann generieren Sie von einem Computer aus, auf dem das Zertifikat installiert werden soll, eine Zertifikatsanforderung (Certificate Signing Request, CSR). Diese wird bei der internen CA eingereicht, um ein Code-Signing-Zertifikat zu erhalten. Dies kann je nach CA-Konfiguration automatisch oder manuell geschehen. Nach Genehmigung und Ausstellung des Zertifikats durch die CA installieren Sie das erhaltene Zertifikat auf dem System, von dem aus Sie die Anforderung gestellt haben. Daraufhin können Sie damit PowerShell-Skripte signieren.
Neben dem Verwenden eines CA-Zertifikats können Sie auch sogenannte SelfSigned-Zertifikate nutzen. Diese sind von derselben Entität (eigener Client oder Server) erstellt und signiert, die sie auch verwendet. Sie sollten aufgrund des inhärenten Misstrauens in der Praxis nicht zum Einsatz kommen, sind jedoch zu Demonstrations- und Testzwecken in nicht-produktiven Umgebungen geeignet. Ein solches Zertifikat erstellen Sie mithilfe der PowerShell wie folgt:
s$Fqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName
$certParams = @{
DnsName = $Fqdn
Type = "CodeSigningCert"
CertStoreLocation = "Cert:\CurrentUser\My"
}
$cert = New-SelfSignedCertificate @certParas
Anschließend sollten Sie das Zertifikat den vertrauenswürdigen Stammzertifizierungsstellen hinzufügen, sodass das Betriebssystem und andere Anwendungen dieses Zertifikat als vertrauenswürdig betrachten:
$trustParams = @{
Certificate = $cert
CertStoreLocation = "Cert:\LocalMachine\Root"
}
Import-Certificate @trustParams
Anschließend erfolgt die Signatur über:
$signParams = @{
FilePath = "<Pfad\zum\Script.ps1>"
Certificate = $cert
}
Set-AuthenticodeSignature @signParams
Sie prüfen den Erfolg via:
Get-AuthenticodeSignature -FilePath "<Pfad\zum\Script.ps1>"
2. Sicherheit beim Fernzugriff
Eine der größten Stärken der PowerShell ist ihre Remotefähigkeit (PS-Remoting). Diese erlaubt das Fernsteuern von mehreren hundert Servern oder Clients, wodurch die Administration von Windows-Umgebungen erheblich skaliert. Insbe- sondere bei der Verwaltung kritischer Systeme wie Domaincontroller (DC) oder anderer Produktivsysteme ist eine Verschlüsselung der Kommunikationskanäle unerlässlich, um die Preisgabe sensibler Informationen und Man-in-the-Middle-Attacken zu unterbinden. Die beiden zentralen Absicherungsoptionen sind das Whitelisting mit einer Zugriffsbeschränkung auf einzelne IP-Adressen oder Netzwerkbereiche und die Verschlüsselung der Verbindung.
Selbstverständlich besteht die Möglichkeit, Zugriffe auf bestimmte Hosts (wie Admin-Clients oder Jump-Hosts) konventionell durch eine Firewallregel zu beschränken. PS-Remoting basiert, solange nicht auf SSH umgestellt, auf dem Windows Remote Management (WinRM). Der Standardport für HTTP ist 5985 und für HTTPS 5986. Über reine Firewallregeln hinaus können Sie den Zugriff auch mittels PowerShell-Bordmitteln beschränken. Just Enough Administration (JEA) ist eine Sicherheitstechnologie, die es ermöglicht, genau zu spezifizieren, welche Aktionen ein Benutzer auf einem Server innerhalb einer PowerShell-Session durchführen darf. Mit JEA ist ein rollenbasiertes Zugriffssystem möglich, um die Nutzung der PowerShell zu limitieren, sodass Anwender nur die für ihre Rolle notwendigen Befehle und Aktionen ausführen können.
Für die Konfiguration von JEA starten Sie mit dem Erstellen von Rollendefinitionen, wobei Sie festlegen, welche Befehle (Cmdlets, Funktionen, Skripte et cetera) die Benutzer ausführen dürfen. Dann legen Sie Sitzungskonfigurationsdateien an, in denen Sie die Rollendefinitionen referenzieren. Gleichzeitig weisen Sie den Benutzern ihre Rollen zu. Schließlich gilt es, die Sitzungskonfiguration zu registrieren, was Sie mit Register-PSSessionConfiguration
erledigen.
Schauen wir uns nun das Anlegen von Rollen im Detail an: Sie erzeugen zunächst eine Datei mit der Endung PSRC und definieren darin die erlaubten Cmd-lets. Die folgende Beispieldatei beschränkt die Nutzung auf die Get-Process- und Get-Service-Cmdlets:
"MyJEARole.psrc"
RoleCapabilities = @{
VisibleCmdlets = 'Get-Process', 'Get-Service'
}
}
# "MyJEARole.psrc"
@{
RoleCapabilities = @{
VisibleCmdlets = 'Get-Process', 'Get-Service'
}
}
Legen Sie nun eine Sitzungskonfigurationsdatei mit der Endung PSSC an. Diese enthält Informationen über die Konfiguration der Sitzung und spezifiziert die betroffene Benutzergruppe:
# "MyJEASession.pssc"
SessionType = 'RestrictedRemoteServer'
RunAsVirtualAccount = $tr
RoleDefinitions = @{
'DOMAIN\SomeUserGroup' = @{
RoleCapabilities = 'MyJEARole'
# "MyJEASession.pssc"
@{
SessionType = 'RestrictedRemoteServer'
RunAsVirtualAccount = $true
RoleDefinitions = @{'DOMAIN\SomeUserGroup' = @{
RoleCapabilities = 'MyJEARole'
}
}
}
Die verschiedenen Konfigurationsoptionen verstehen sich wie folgt:
- SessionType RestrictedRemoteServer: Gibt an, dass diese Sitzung eine eingeschränkte Umgebung ist, in der nur die in der Rollenfähigkeitsdatei definierten Befehle und Funktionen verfügbar sind.
- RunAsVirtualAccount=$true: Alle Befehle in der Sitzung werden unter einem temporären und lokalisierten Konto ausgeführt, das nicht im Active Directory existiert. Es hat die Berechtigungen des Computers, auf dem es läuft.
- RoleDefinitions: Enthält die Zuweisungen von AD-Benutzer-/Gruppen zu den spezifischen Rollen, die Sie zuvor in der PSRC-Datei definiert haben.
Nun registrieren Sie die Konfiguration:
$params = @{
Name = 'MyJEASession'
Path = '.\MyJEASession.pssc'
Force = $true
}
Register-PSSessionConfiguration @params
Dieses Beispiel illustriert nur einen Ausschnitt der Möglichkeiten, die JEA bietet, liefert jedoch einen prägnanten Einblick in seine Funktionsweise.
3. Sicherheit durch Verschlüsselung
Um die Sicherheit von PS-Remoting zu gewährleisten, ist die Verschlüsselung der Kommunikation von essentieller Bedeutung. Für WinRM funktioniert diese über HTTPS und erfordert ein SSL-Zertifikat. In produktiven Umgebungen empfiehlt es sich, dies über die eigene CA zu tun. Zur Vereinfachung des Beispiels greifen wir jedoch erneut auf die Verwendung eines SelfSigned-Zertifikats zurück:
$Fqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName
$params = @{
CertstoreLocation = 'Cert:\LocalMachine\My'DnsName = $Fqdn
}
$Cert = New-SelfSignedCertificate @params
$Thumbprint = $Cert.Thumbprint
Um sicherzustellen, dass zukünftig keine Verbindungen über HTTP aufgebaut werden, sollten Sie den HTTP-Eintrag komplett entfernen:
dir WSMan:\Localhost\listener | where Keys -eq "Transport=HTTP" |` Remove-Item -Recurse
Mithilfe des Thumbprints erstellen Sie danach den neuen HTTPS-Listener:
New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Thumbprint -Force
Es ist wichtig, die Windows-Firewall entsprechend anzupassen. Dies ist notwendig, da die Aktivierung von PS-Remoting mit dem Befehl Enable-PSRemoting
ausschließlich Regeln für den Traffic über HTTP festlegt. Natürlich lässt sich dies neue Firewallregel auch mittels PowerShell-Befehl erstellen:
$firewallRuleParams = @{
DisplayName = "WinRM HTTPS"
Name = "WinRM HTTPS"
Profile = "Any"
LocalPort = 5986
Protocol = "TCP"
}
New-NetFirewallRule @firewallRuleParams
Bei Verwendung eines SelfSigned-Zertifikats müssen Sie nun sicherstellen, dass der Client, der eine PSRemoting-Sitzung zum Server aufbaut, über dieses Zertifikat verfügt. Die Installation des Zertifikats auf dem Client führen Sie wie folgt durch:
Import-Certificate -Filepath "C:\temp\cert" -CertStoreLocation "Cert:\LocalMachine\Root"
Anschließend stellen Sie mit dem Parameter "UseSSL" eine verschlüsselte Verbindung zum Remote-Device her:
Enter-PSSession -ComputerName *FQDNofServer* -UseSSL
4. Anmeldedaten verwalten
Die Klartextspeicherung von Zugangsdaten in PowerShell-Skripten kann ein erhebliches Sicherheitsrisiko darstellen, wie der Uber-Hack im September 2022 gezeigt hat. Das SecretManagement-Modul der PowerShell bietet jedoch eine robuste Möglichkeit, sensible Informationen sicher in einem internen Vault zu speichern oder auf externe Passwortmanager zuzugreifen.
Zur Verwendung müssen Sie das Modul sowie einen spezifischen Speicher wie den SecretStore installieren und konfigurieren:
Install-Module -Name Microsoft.PowerShell.SecretManagement
Install-Module -Name Microsoft.PowerShell.SecretStore
Es folgt die Einrichtung eines Vaults:
$params = @{
Name = 'SecretStore'
ModuleName = 'Microsoft.PowerShell.SecretStore'
DefaultVault = $true
}
Register-SecretVault @params
Set-SecretStoreConfiguration -Authentication Password
Nach der Einrichtung wird ein Passwort benötigt, um den Vault zu entschlüsseln und Zugang zu gespeicherten Passwörtern zu erhalten. Über die Set-Secret- und Get-Secret-Cmdlets können Sie Secrets speichern und abrufen. Standardmäßig werden Secrets als SecureStrings gespeichert. Sofern Sie die Secrets aber als reine Strings hinterlegen wollen, erledigen Sie dies beim Speichern über den Parameter "-AsPlainText":
# Speichern des Secrets
Set-Secret -Name 'MyAPIKey' -Secret '<12345abcde>' -Vault 'SecretStore' (-AsPlainText)
# Auslesen des Secrets
$mySecret = Get-Secret -Name 'MyAPIKey' -Vault 'SecretStore'
Optimierter Workflow mit Secret-Management
Für produktive Arbeitsumgebungen ergeben sich spezielle Herausforderungen und Anforderungen, insbesondere in Bezug auf verteilte Systeme und das automatisierte Abrufen von Secrets. Hier können verschiedene Secret-Manager und Vault-Produkte wie KeePass oder Azure Key Vault und spezifische Konfigurationen wie zum Beispiel das automatisierte Entschlüsseln des Vaults ins Spiel kommen.
Der SecretStore und das dazugehörige Modul stellen nur einen Weg der Speicherverwaltung dar. So ist das SecretManagement-PS-Modul in der Lage, mit anderweitigen Secret-Managern zu kommunizieren. Der beste Weg, um kompatible Secret-Manager ausfindig zu machen, führt über die PowerShell-Gallery [2], in der Sie kompatible Anbieter über die Suche nach "Secret-Management” aufspüren.
Das folgende Beispiel bezieht sich auf die Verwendung von KeePass als Backend. Dazu müssen Sie zunächst das entsprechende Modul installieren und den Vault registrieren:
Install-Module -Name SecretManagement.KeePass
$VaultParams = @{Path = "./keepass.kdbx"
UseMasterPassword = $true
}
$params = @{
Name = 'SecretStore'
ModuleName = 'SecretManagement.keepass'
VaultParameters = $VaultParams
}
Register-SecretVault @params
Bei automatisierten Prozessen stellt die Passwortabfrage zur Entschlüsselung des Vaults eine Herausforderung dar. Hier gibt es verschiedene Lösungen, abhängig von der spezifischen Plattform und den Anforderungen. Ein Weg ist, das Master-Passwort sicher über interne Speichermöglichkeiten zu übergeben oder als Umgebungsvariable zu setzen:
$env:VAULT_PASSWORD = "IhrSicheresPasswort"
$params = @{
String = $env:VAULT_PASSWORD
AsPlainText = $true
Force = $true
}
$SecurePassword = ConvertTo-Secure-String @params
Unlock-SecretStore -Password $SecurePassword
5. Audit und Logging der PowerShell
Die Protokollierung von PowerShell-Aktivitäten ist ein entscheidender Aspekt, um Systemänderungen oder durchgeführte Operationen nachzuvollziehen. Durch das PowerShell-Logging können Sie verdächtige Aktionen schneller erkennen und untersuchen.
PowerShell-spezifische Logs sind im Eventlog unter "Microsoft-Windows-PowerShell / Operational" gespeichert und Sie können diese mit folgendem Befehl betrachten (der hintere Teil beschränkt die Ausgabe auf fünf Events):
Get-WinEvent -LogName Microsoft-Windows-PowerShell/Operational | Select-Object -First 5
Die zu loggenden Events sind frei konfigurierbar und bieten Ihnen die folgende Optionen:
- EnableModuleLogging: Steuert die Modulprotokollierung und zeichnet Cmdlets, Funktionen, Workflows und Skriptblock-Aktivierungen auf.
- EnableScriptBlockLogging: Schaltet die Skriptblock-Protokollierung ein oder aus und protokolliert alle ausgeführten Skriptblöcke.
- EnableScriptBlockInvocationLogging: Aktiviert die Protokollierung von Skriptblock-Aufrufen und legt zusätzliche Details zu diesen ab.
- EnableTranscripting: Schaltet die Trans-kription ein oder aus und zeichnet alle Eingaben und Ausgaben der PowerShell-Sitzung in einer Textdatei auf.
- EnableInvocationHeader: Fügt bei aktivierter Transkription einen Kopfzeilenkommentar mit Zeitstempel und Benutzernamen zu jedem Skriptblock hinzu.
- OutputDirectory : Legt den Speicherort für Transkriptionsdateien fest.
Die Einstellungen für das Logging konfigurieren Sie über die Gruppenrichtlinienverwaltung und verteilen sie mittels GPOs. Dazu öffnen Sie die Gruppenrichtlinienverwaltung (gpedit.msc) und navigieren zu "Computerkonfiguration / Administrative Vorlagen / Windows-Komponenten/ Windows PowerShell". Hier definieren Sie die gewünschten Einstellungen wie beispielsweise "Modulprotokollierung aktivieren" oder "Skriptblockprotokollierung aktivieren".
Fazit
Die gezeigten Sicherheitsprinzipien und -praktiken im Umgang mit PowerShell machen deutlich, dass eine umfassende Sicherheitsstrategie auch beim Scripting essenziell ist, um die vielfältigen Bedrohungen zu adressieren. Die hier vorgestellten Ansätze bilden dennoch eine solide Basis, um Ihre Skripte auf sichere Beine zu stellen.
(jp)