Überblick
Die PowerShell ist ein Bestandteil des Betriebssystems. Daher sorgt ein generelles Blockieren nur für scheinbare PowerShell Sicherheit. Den besten Schutz versprechen die Schutz- und Protokollierungs-Mechanismen von PowerShell selbst.
In diesem Artikel beleuchte wir das Thema PowerShell Sicherheit aus dem Blickwinkel eines Administrators. Wie PowerShell produktiv abgesichert wird, um trotzdem administrative Aufgaben an Nicht-Administratoren zu delegieren (Just Enough Administration). Auch geht es darum verdächtige und unerwünschte Aktivitäten zu protokollieren (ScriptBlockLogging).
TIPP - Neben der administrativen Absicherung, um die PowerShell Sicherheit zu erhöhen, sollten Sie auch mit sensiblen Daten wie Zugangsdaten, Geheimnisse und Zugangsbeschränkungen entsprechend umgehen und schützen. Wie Sie das in PowerShell realisieren, finden Sie im Artikel "Mit Sicherheit in der PowerShell umgehen".
INTERESSANT - Eine gründliche Analyse der Sicherheittechnologie zwischen verfügbaren Shells und Skriptsprachen finden Sie in dem Artikel Ein Vergleich der Sicherheit von Shell und Skriptsprache.
Unbedingt sollten Sie PowerShell 2.0 deinstallieren. Mit dieser alten Shell-Version lassen sich alle wesentlichen Restriktionen für PowerShell unterlaufen. Das optionale Feature ist vorinstalliert und kann aber ab Windows 8.1 und Server 2012 deinstalliert werden.
Statische Strings erhöht die Sicherheit! Grundsätzlich immer die einfachen Hochkommas '
verwenden. Es seiden man verwendet Variable im String, erst dann die doppelten Hochkommas "
verwenden. Das erhöht die Sicherheit da die Gefahr von String-Injection minimiert wird.
# ! FALSCH
$Ort = "Würzburg"
# RICHTIG
$Ort = 'Würzburg'
$s = 'Hallo $Ort!'
# vs.
$s = "Hallo $Ort!"
Ausführungsrichtlinien korrekt konfigurieren
Die Ausführungsrichtlinie (ExecutionPolicy) ist ein PowerShell Sicherheit-Funktion, die steuert unter welchen Bedingungen Konfigurations- und Skript-Dateien ausgeführt werden. Die Ausführungsrichtlinien schränken Benutzeraktionen nicht ein. Stattdessen helfen die Ausführungsrichtlinien Benutzern, dass sie nicht unbeabsichtigt gegen diese Regeln verstoßen.
WICHTIG - Das Verändern der Ausführungsrichtlinien stellt NUR einen Schutz vor dem unbedarften Ausführen von Skripts dar - MEHR NICHT!
# READ betroffene About-Seiten:
Get-Help -Name 'about_Execution_Policy' -ShowWindow
# ? Wie ist der aktuelle Status der Ausführungsrichtlinien:
Get-ExecutionPolicy -List
# ? Wie ist die Ausführungsrichtlinie für den aktuellen Script-Host eingestellt:
$env:PSExecutionPolicyPreference
Empfohlene Einstellung für Client und Server: Alle ausführbaren Dateien müssen mit einem x.509-Zertifikat signiert sein.
Set-ExecutionPolicy -ExecutionPolicy 'AllSigned' -Force
Empfohlene Einstellung für Test- und Entwicklungs-Systeme: Alle ausführbaren Dateien die Remote (z.B. per Download oder UNC-Pfad, etc.) auf den PC gelangt sind, müssen mit einem X.509-Zertifikat signiert sein. Diese Dateien werden an einem 'Download-Marker' identifiziert. Dieser kann per Cmdlet Unblock-File
wieder entfernt werden.
Set-ExecutionPolicy -ExecutionPolicy 'RemoteSigned' -Force
Für das automatische Ausführen von signierten Skripten müssen folgende Voraussetzungen erfüllt sein.
- Das X.509-Zertifikat muss von einer "Vertrauenswürdigen Stammzertifizierungsstelle" (
Root
) abstammt ODER es ist selbst in Root abgelegt! - Das X.509-Zertifikat muss im Zertifikatspeicher für "Vertrauenswürdige Herausgeber" (
TrustPublisher
) enthalten ist.
Ausführungsrichtlinien per GPO steuern: Die Ausführungsrichtlinien können komfortable per GPO eingestellt werden. Diese wiederum manipulieren folgende Registry-Schlüssel.
Get-ItemPropertyValue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\ShellIds\Microsoft.PowerShell' -Name 'ExecutionPolicy'
Get-ItemPropertyValue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\ShellIds\ScriptedDiagnostics' -Name 'ExecutionPolicy'
Get-ItemPropertyValue -Path ''Registry::HKEY_CURRENT_USER\Software\Microsoft\PowerShell\ShellIds\Microsoft.PowerShell -Name 'ExecutionPolicy'
Skript benötigt erhöhte Admin-Rechte
Im administrativen Umfeld ist nötig, dass Skripte mit erhöhte Admin-Rechte laufen. Zum Skript-Beginn kann man überprüfen ob die Admin-Rechte vorhanden sind. Sollte dies nicht der Fall sein so könnte das Skript zu beginn abbrechen, anstatt fehlerhaft in der Mitte auszusteigen.
$IsElevatedAdminRights = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]'Administrator')
if(-not $IsElevatedAdminRights) {
throw 'Vorgang abgebrochen! Es werden erhöhte administrative Berechtigungen benötigt!'
} else {
'Dieses Skript läuft mit erhöhten Admin-Berechtigungen!' | Write-Warning
}
PowerShell PKI-Handling
# READ betroffene Cmdlets:
Get-Command -Name '*' -Module 'PKI'
# ! Zertifikat erstellen:
using namespace 'Microsoft.CertificateServices.Commands'
$params = @{
FriendlyName = 'Superman'
Subject = 'CN=_Superman (Doctor S. Man), E=s.man@krypton.universe'
HashAlgorithm = 'SHA512'
KeyAlgorithm = 'RSA'
KeyLength = 4096
KeyExportPolicy = [KeyExportPolicy]::ExportableEncrypted
KeySpec = [KeySpec]::KeyExchange
CertStoreLocation = 'Cert:\CurrentUser\My'
Type = [CertificateType]::Custom
TextExtension = @('2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4,1.3.6.1.5.5.7.3.5,1.3.6.1.5.5.7.3.6,1.3.6.1.5.5.7.3.7,1.3.6.1.5.5.7.3.8,1.3.6.1.5.5.7.3.9,1.3.6.1.4.1.311.80.1,1.3.6.1.4.1.311.10.3.4,1.3.6.1.4.1.311.10.3.4.1', `
'2.5.29.17={text}email=s.man@krypton.universe&upn=s.man@krypton.universe')
NotAfter = (Get-Date).AddMinutes(60)
AlternateSignatureAlgorithm = $true
}
$myPfxCert = New-SelfSignedCertificate @params
# ! Zertifikat exportieren:
$myPfxCert | Export-PfxCertificate -Password (Read-Host -Prompt 'Set PFX-Password for Superman' -AsSecureString) -FilePath 'C:\Temp\Superman.pfx'
$myPfxCert | Export-Certificate -Type 'CERT' -Force -FilePath 'C:\Temp\Superman.cer'
# ! Zertifikat im Zertifikats-Speicher löschen:
Get-ChildItem -Path 'Cert:\CurrentUser' -Recurse | Where-Object -Property 'Thumbprint' -CEQ $myPfxCert.Thumbprint | Remove-Item -Force -Recurse
# ! Zertifikat importieren:
Import-Certificate -FilePath 'C:\Temp\Superman.cer' -CertStoreLocation 'Cert:\LocalMachine\Root'
Import-PfxCertificate -FilePath 'C:\Temp\Superman.pfx' -CertStoreLocation 'Cert:\CurrentUser\My' -Password (Read-Host -Prompt 'PFX-Password for Superman' -AsSecureString)
# ! Zertifikat aus dem Dateisystem lesen und auf Verwendungszweck testen:
Get-PfxData -Password (Read-Host -Prompt 'PFX-Password for Superman' -AsSecureString) -FilePath 'C:\Temp\Superman.pfx' | Format-List -Property '*'
$test = Get-PfxCertificate -FilePath 'C:\Temp\Superman.pfx'
Test-Certificate -Cert $test -Policy 'SSL' | Write-Warning
Test-Certificate -Cert $test -EKU '1.3.6.1.5.5.7.3.1' | Write-Warning # = Server Authentication
# ! Zertifikat aus dem Cert-Speicher lesen und auf Verwendungszweck testen:
Get-ChildItem -Path 'Cert:\CurrentUser\My' | Where-Object -Property 'Subject' -CLike -Value 'CN=_Superman (Doctor S. Man), E=s.man@krypton.universe' | Test-Certificate -Policy 'SSL' | Write-Warning
Get-ChildItem -Path 'Cert:\LocalMachine\Root' | Where-Object -Property 'Subject' -CLike -Value 'CN=_Superman (Doctor S. Man), E=s.man@krypton.universe' | Test-Certificate -EKU '1.3.6.1.5.5.7.3.1' | Write-Warning
# TODO Aufräumen:
Remove-Item -Path 'C:\Temp\Superman.*' -Force
Get-ChildItem -Path 'Cert:\LocalMachine\', 'Cert:\CurrentUser\' -Recurse | Where-Object -Property 'Subject' -CLike -Value 'CN=_Superman (Doctor S. Man), E=s.man@krypton.universe' | Remove-Item -Force
PowerShell Script-Dateien signieren
Warum sollte man signieren:
- Eine Signatur schützt ein Skript (.PS1, .PSM1, .PS1XML, ...) vor Manipulation und erhöht so die PowerShell Sicherheit!
- Der Signierer bestätigt mit seiner Signatur den endgültigen Status des Skriptes!
- Dritte können erkennen wer dieses Skript signiert / erstellt hat.
PowerShell kann über die Ausführungsrichtlinien so konfiguriert werden (AllSigned
), dass nur Skripte ausgeführt werden, wenn folgende Voraussetzungen erfüllt sind:
- Die Skriptdatei wurde mit einem X.509-Zertifikat signiert!
- Die signierte Datei wurde anschließend nicht manipuliert!
- Das Signierer-Zertifikat stamm von einer "Vertrauenswürdigen Stammzertifizierungsstelle" (
Root
) ab ODER es ist selbst in Root abgelegt worden! - Signierer-Zertifikat wurde zusätzlich im Zertifikatspeicher für "Vertrauenswürdige Herausgeber" (
TrustPublisher
) abgelegt!
Zum Beispiel an einer einfachen Umsetzung über ein selbstsigniertes Zertifikat:
# ! 1. Testumgebung vorbereiten
# Ausführungsrichtlinien auf AllSigned setzen
Set-ExecutionPolicy -ExecutionPolicy 'AllSigned' -Scope 'Process' -Force
Set-ExecutionPolicy -ExecutionPolicy 'AllSigned' -Scope 'CurrentUser' -Force
Set-ExecutionPolicy -ExecutionPolicy 'AllSigned' -Scope 'LocalMachine' -Force
# PKI Modul importieren
Import-Module -Name 'PKI' # Windows PowerShell
Import-WinModule -Name 'PKI' # bzw. PowerShell 7
# Test-Ordner C:\Temp erstellen
New-Item -Path 'C:\Temp' -ItemType 'Directory' -Force | Set-Location
# Test-Script erzeugen
'"> > > Execute Code from .PS1-Script! at $(Get-Date) < < <" | Write-Warning' | Set-Content -Path '.\Test.ps1' -Force
# ! 2. Aktuell wird das Ausführen des Skriptes mit einer Fehlermeldung abgebrochen
. '.\Test.ps1'
# ! 3. Signierer-Zertifikate erstellen:
$params = @{
Subject = 'CN=_FirstName_LastName (PS Developer), E=f.lastname@abc.local'
HashAlgorithm = 'SHA512'
KeyExportPolicy = [Microsoft.CertificateServices.Commands.KeyExportPolicy]::ExportableEncrypted
CertStoreLocation = 'Cert:\CurrentUser\My'
Type = [ Microsoft.CertificateServices.Commands.CertificateType]::CodeSigningCert
NotAfter = (Get-Date).AddYears(5)
}
$myPfxCert = New-SelfSignedCertificate @params
# ! 4. Aus dem Signierer-Zertifikat ein öffentliches Zertifikat erstellen:
$myPfxCert | Export-Certificate -FilePath '.\PublicSignerCertificate.cer' -Type 'CERT' -Force
# ! 5. Vertrauensstellung einrichten:
# 1. im Zertifikatsspeicher Root abgelegt werden, um dem Zertifikat generell zu vertrauen
Import-Certificate -FilePath '.\PublicSignerCertificate.cer' -CertStoreLocation 'Cert:\LocalMachine\Root'
# 2. im Zertifikatsspeicher TrustedPublisher abgelegt werden, um den signierten .PS1-Dateien im Besonderen zu vertrauen
Import-Certificate -FilePath '.\PublicSignerCertificate.cer' -CertStoreLocation 'Cert:\LocalMachine\TrustedPublisher'
# ! 6. Das eigentliche Script signieren:
$params = @{
Certificate = $myPfxCert
HashAlgorithm = 'SHA512'
TimestampServer = 'http://timestamp.globalsign.com/scripts/timstamp.dll'
FilePath = '.\Test.ps1'
}
Set-AuthenticodeSignature @params
# ! 7. Signiertes Script testen:
# ? Die digitale Signatur sollte GÜLTIG sein?
Get-AuthenticodeSignature -FilePath '.\Test.ps1' | Format-List -Property *
# ? Wird .PS1-Datei nun problemlos ausgeführt?
. '.\Test.ps1'
# ! 8. Aufräumen
Set-ExecutionPolicy -ExecutionPolicy 'RemoteSigned' -Scope 'Process' -Force
Set-ExecutionPolicy -ExecutionPolicy 'RemoteSigned' -Scope 'CurrentUser' -Force
Set-ExecutionPolicy -ExecutionPolicy 'RemoteSigned' -Scope 'LocalMachine' -Force
Get-ChildItem -Path 'Cert:\CurrentUser\My', 'Cert:\LocalMachine\Root', 'Cert:\LocalMachine\TrustedPublisher' | Where-Object Thumbprint -CEQ $myPfxCert.Thumbprint | Remove-Item
Get-ChildItem -Path '.\Test.ps1', '.\PublicSignerCertificate.cer' | Remove-Item
TIPP - Vielleicht besitzen Sie ja schon ein entsprechendes Zertifikat zum Signieren. Lassen Sie sich diese wie folgt anzeigen.
Get-ChildItem -Path 'Cert:\CurrentUser\My' -CodeSigningCert
Einfache Host-Ein-/Ausgabe Protokollierung
Eine einfache Variante, um die PowerShell Sicherheit zu erhöhen, ist das Mitschneiden sämtlicher Aktivitäten und deren Resultate auf einem PowerShell Host. Hierzu verwenden Sie die Cmdlets Start-Transcript
und Stop-Transcript
.
# * 1. Transcript starten:
Start-Transcript -Path "C:\Temp\PsHost.log" -Append -Force
# * 2. Test-Eingabe & -Ausgaben erzeugen:
Get-Process
Read-Host -Prompt "Passwort eingeben" -AsSecureString
# * 3. Transcript stoppen:
Stop-Transcript -Verbose
# 4. Log-Datei Anzeigen:
Start-Process -FilePath "C:\Temp\PsHost.log"
Wo und wann Sie Start-Transcript
initiieren obliegt Ihnen. Denkbar wäre z.B. einer der Autostartdateien (profile.ps1
).
Aktivitäten mittels ScriptBlockLogging protokollieren
Wenn ScriptBlockLogging
aktiviert ist werden sämtliche Befehle zu PowerShell-Vorgängen protokolliert. Durch den lückenlosen Nachweis sämtlicher PowerShell-Aktivität wir die PowerShell Sicherheit weiter erhöht.
WICHTIG - Bzgl. PowerShell 7: Bevor Ereignisse in das Ereignisprotokoll geschrieben werden können, muss im Gegensatz zu Linux oder macOS in Windows der Ereignisanbieter registriert sein. Führen Sie dazu mit erhöhten Berechtigungen folgendes aus.
. "$PsHome\RegisterManifest.ps1"
Get-WinEvent -ListProvider '*powershell*' | Select-Object -Property 'Name'
Permanentes und sicheres Protokollieren sämtlicher Host-Aktivitäten mittels ScriptBlockLogging
aktivieren.
TIPP -
ScriptBlockLogging
per GPO unterComputerkonfiguration / Administrative Vorlagen / Windows-Komponenten / Windows PowerShell / Protokollierung von PowerShell-Scriptblöcken
aktivieren. ACHTUNG - z.Zt. nur für Windows PowerShell, andere Versionen nur per folgenden Registry-Keys.
# ! Für PowerShell 7 und PowerShell Core:
New-Item -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\PowerShellCore' -Name 'ScriptBlockLogging' -ItemType 'Key' -Force | New-ItemProperty -Name 'EnableScriptBlockLogging' -Value 1 -PropertyType 'DWord' -Force
# ! Für Windows PowerShell:
New-Item -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell' -Name 'ScriptBlockLogging' -ItemType 'Key' -Force | New-ItemProperty -Name 'EnableScriptBlockLogging' -Value 1 -PropertyType 'DWord' -Force
# ! Für Windows PowerShell 32it: Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
# ! Für PowerShell Core 32bit: Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Policies\Microsoft\Windows\PowerShellCore\ScriptBlockLogging
Die so protokollierten Aktivitäten können nun wie folgt ausgewertet werden.
# Test-Code der gleich im Protokoll auftaucht:
Get-ChildItem -Path 'C:\Temp'
# ! Auswertung:
Get-WinEvent -ListLog '*powershell*'
Get-WinEvent -FilterHashtable @{ LogName='PowerShellCore/Operational' ; Id="4104" } | Select-Object -Property 'RecordId', 'ProcessId', 'MachineName', 'UserId', 'TimeCreated', 'Message' | Where-Object -Property 'Message' -IMatch -Value 'Get-ChildItem'
# TODO Aufräumen:
. "$PsHome\RegisterManifest.ps1" -Unregister
Remove-Item -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\PowerShellCore\ScriptBlockLogging' -Recurse -Force
Remove-Item -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging' -Recurse -Force
TIPP - Um die PowerShell Sicherheit weiter zu erhöhen, sollten sensible Daten im Protokoll geschützt werden. Dazu verschlüsseln Sie einfach die Logs (s. Protected Event Logging unter
Get-Help -Name 'about_logging_windows' -ShowWindow
).
Aktivitäten in der PowerShell-Session einschränken (LanguageMode)
Über $ExecutionContext.SessionState.LanguageMode
können Sie weiter einschränken welche Cmdlets, Typen und Interaktionen erlaubt sind, um die PowerShell Sicherheit weiter zu erhöhen.
# ! Zum Beispiel aktivieren per Autostart über eine der folgenden Dateien:
$profile.AllUsersAllHosts
$profile.AllUsersCurrentHost
# ! 1. Keine Anwendungen und Skripte ab jetzt erlauben:
$ExecutionContext.SessionState.Applications.Clear()
$ExecutionContext.SessionState.Scripts.Clear()
# ! 2. Erlaubte Cmdlets festlegen und die restlichen Cmdlets unsichtbar machen:
$allowedCommands = @()
$allowedCommands += "ForEach-Object"
$allowedCommands += "Get-ChildItem"
$allowedCommands += "Get-Command"
$allowedCommands += "Get-Member"
$allowedCommands += "Get-Module"
$allowedCommands += "Out-Default"
$allowedCommands += "Select-Object"
$allowedCommands += "Test-NetConnection"
$allowedCommands += "Where-Object"
Get-Command -CommandType "Cmdlet", "Function" | Where-Object -Property Name -NotIn -Value $allowedCommands | ForEach-Object -Process { $_.Visibility = "Private" }
# ! 3. Den LanguageMode in den beschränkten Sprachmodus versetzen:
$ExecutionContext.SessionState.LanguageMode = "RestrictedLanguage"
Weitere LanguageMode
-Details entnehmen Sie den entsprechenden About-Seiten.
# READ siehe auch:
Get-Help -Name 'about_Language_Modes' -ShowWindow
Get-Help -Name 'about_FullLanguage' -ShowWindow
Get-Help -Name 'about_RestrictedLanguage' -ShowWindow
Get-Help -Name 'about_ConstrainedLanguage' -ShowWindow
Um zu ermitteln in welchem Modi sich die aktuelle Sitzung befindet, können Sie die LanguageMode
Eigenschaft abfragen:
$ExecutionContext.SessionState.LanguageMode
Zu den wichtigsten PowerShell Sicherheits-mechanismen gehört der Constrained Language Mode
(CLM) die mehrere gefährlichen PowerShell-Features deaktiviert und so deren Missbrauch minimiert und die PowerShell Sicherheit erhöht. Der ConstrainedLanguage
-Modus erlaubt alle Cmdlets und alle PowerShell-Sprachelemente, begrenzt jedoch die zulässigen Typen.
Wenn der LanguageMode
auf ConstrainedLanguage
steht werden folgende wichtige Funktionen geboten:
- Alle Cmdlets in Windows-Modulen und andere von UMCI genehmigte Cmdlets sind voll funktionsfähig und haben, sofern nicht anders angegeben, vollständigen Zugriff auf Systemressourcen.
- Alle in Windows enthaltenen Module können importiert und alle Befehle, die die Module exportieren, in der Sitzung ausgeführt werden.
- Das Cmdlet
Add-Type
kann signierte Assembly laden, jedoch keinen beliebigen C# -Code oder Win32-APIs. - Das Cmdlet
New-Object
kann nur für zulässige Typen verwendet werden (siehe unten). - Die Typkonvertierung ist zulässig, jedoch nur, wenn das Ergebnis ein zulässiger Typ ist.
- Cmdlet-Parameter, die Zeichenfolgeneingaben in Typen konvertieren, funktionieren nur, wenn der resultierende Typ ein zulässiger Typ ist.
- Es sind nur folgende COM-Objekte zulässig:
Scripting.Dictionary
Scripting.FileSystemObject
VBScript.RegExp
Die folgenden Typen sind im ConstrainedLanguage
-Modus zulässig. Benutzer können Eigenschaften abrufen, Methoden aufrufen und Objekte in diese Typen konvertieren.
[AliasAttribute]
, [AllowEmptyCollectionAttribute]
, [AllowEmptyStringAttribute]
, [AllowNullAttribute]
, [Array]
, [Bool]
, [byte]
, [char]
, [CmdletBindingAttribute]
, [DateTime]
, [decimal]
, [DirectoryEntry]
, [DirectorySearcher]
, [double]
, [float]
, [Guid]
, [Hashtable]
, [int]
, [Int16]
, [long]
, [ManagementClass]
, [ManagementObject]
, [ManagementObjectSearcher]
, [NullString]
, [OutputTypeAttribute]
, [ParameterAttribute]
, [PSCredential]
, [PSDefaultValueAttribute]
, [PSListModifier]
, [PSObject]
, [PSPrimitiveDictionary]
, [PSReference]
, [PSTypeNameAttribute]
, [Regex]
, [SByte]
, [string]
, [SupportsWildcardsAttribute]
, [SwitchParameter]
, [System.Globalization.CultureInfo]
, [System.Net.IPAddress]
, [System.Net.Mail.MailAddress]
, [System.Numerics.BigInteger]
, [System.Security.SecureString]
, [TimeSpan]
, [UInt16]
, [UInt32]
, [UInt64]
Seit PowerShell 5 wird automatisch erkannt ob in den Constrained Language Mode
gewechselt werden soll. Die PowerShell legt dazu unter $env:TEMP
temporär ein Script an und versucht dieses auszuführen. Wird die PowerShell bei der Ausführung gehindert, startet sie im eingeschränkten Sprach-modus. Dazu müssen Sie lediglich das Ausführen von Skripten im Ordner $env:TEMP verbieten.
Realisieren können Sie das z.B. per Softwareeinschränkung (GPO) unter Computerkonfiguration / Windows-Einstellungen / Sicherheitseinstellungen / Richtlinien für Softwareeinschränkung / Zusätzliche Regeln
.
# TODO Test-Umgebung: Neu Pfad-Regel erstellen für C:\Users\Attila\AppData\Local\Temp :
GPEdit.msc
Oder per AppLocker unter Computerkonfiguration / Windows-Einstellungen / Sicherheitseinstellungen / Anwendungssteuerungsrichtlinien / AppLocker / Skriptregeln
.
Umgang mit Zugriffsberechtigungen (ACL)
Die PowerShell-Board-Mittel sind leider noch überschaubar. Im Grunde können wir von einem vorhandenes Windows-Objekt, dessen Access-Control-List klonen und genau diese auf ein anderes Objekt übertragen.
# ! Die PowerShell-Board-Mittel:
Get-Command -Name 'Get-Acl', 'Set-Acl', 'ConvertFrom-SddlString'
# ? Berechtigungen von Ordner-A auf Ordner-B übertragen:
New-Item -Path 'C:\' -Name 'TempTest' -ItemType 'Directory' -Force
Get-Acl -Path 'C:\Temp' | Select-Object -Property '*'
Get-Acl -Path 'C:\Temp' | Set-Acl -Path 'C:\TempTest'
# TODO Aufräumen:
Remove-Item -Path 'C:\TempTest' -Recurse -Force
ACL-Objekte sind mit unter oft kryptisch zu lesen (gacutil.exe) aber lesen und auswerten bekommen wir über das Cmdlet ConvertFrom-SddlString
Unterstützung.
# ? Berechtigungen von ACL-Objekten auswerten:
Get-Acl -Path $env:USERPROFILE | Select-Object -ExpandProperty 'Sddl' | ConvertFrom-SddlString
Umfassende/aufwendige Möglichkeiten ergeben sich mit .NET oder Sie schauen Sich das Modul NtfsSecurity
aus der PowerShall-Gallery einmal genauer an.
Install-Module -Name 'NTFSSecurity' -Scope 'CurrentUser' -SkipPublisherCheck -Force -PassThru -Verbose
Get-Command -Module 'NTFSSecurity'
Get-NTFSAccess -Path 'C:\Temp'
# TODO Aufräumen:
Remove-Module -Name 'NTFSSecurity' -Force
Uninstall-Module -Name 'NTFSSecurity' -AllVersions -Force
Admin-Aufgaben an Nicht-Admins delegieren (JEA)
Neben den bereits beschriebenen PowerShell Sicherheit-Mechaniken ist die Königsdisziplin, um die PowerShell Sicherheit auf ein Maximum zu heben das Feature "Just Enough Administration". Dieses vereint die bereits aufgeführten Funktionen und ergänzt diese.
Just Enough Administration (JEA => Gerade genug Administration) ist ein Feature, das ab Windows 10 und Server 2016 zur Verfügung steht. Mit JEA (Just Enough Administration) können Systemverwalter mittels PowerShell granular administrative Aufgaben an Nicht-Administratoren delegieren.
Diese Nicht-Administrator erhalten, unabhängig von der Gruppenmitgliedschaft über eine Remote-Session mittels "Just Enough Administration"-Zugriff auf vorher festgelegte Komponenten (PSProvider, Cmdlets, Cmdlet-Parameter, Ausführbare Dateien, etc.).
Das damit realisierte Prinzip "Least Privilege" sieht vor, nur noch die tatsächlich minimalen Rechte für bestimmte Aufgaben und Dienste an administrative Mitarbeiter zu erteilen.
Die Architektur basiert auf "Just Enough Administration"-Endpoints, mit denen sich der Bediener via Enter-PSSession verbindet und remote Befehle mit höheren Rechten auf Systemen ausführen kann.
Umfassende Details finden Sie in der Microsoft Dokumentation Just Enough Administration.
HINWEIS - Sollten Sie dieses Beispiel unter PowerShell 7 auf Windows-Rechnern ausführen sind folgende Schritte nötig.
Import-WinModule -Name 'NetAdapter'
Import-WinModule -Name 'NetConnection'
Import-WinModule -Name 'Microsoft.PowerShell.LocalAccounts'
1. JEA Voraussetzung und Vorbereitungen
Just Enough Administration ist ein in Feature ab PowerShell 5.0. Dazu gesellen sich noch weitere Voraussetzungen, die wir zuerst einmal abklopfen sollten.
# ? PowerShell-Version:
$PSVersionTable.PSVersion -ge [Version]"5.0.0.0"
# ? OS-Version:
Get-ComputerInfo | ForEach-Object { if(($_.OsName -IMatch 'Windows 10' -and $_.WindowsVersion -ge 1607) -or $_.OsName -IMatch 'Windows Server 2016' -or $_.OsName -imatch 'Windows Server 2019') { $true } else { $false } }
# ? PS Remoting aktiviert:
try { Invoke-Command -ComputerName 'localhost' -ScriptBlock { 1 | Out-Null } -Credential (Get-Credential) -ErrorAction Stop ; $true } catch { $false }
In diesem Artikel Just Enough Administration Voraussetzungen werden die Voraussetzungen erläutert, die erfüllt sein müssen, um "Just Enough Administration" verwenden zu können.
Im folgenden Code-Block treffen wir die Vorbereitungen für das Testszenario. Dieses Szenario kann komplett lokal ausgeführt werden ohne dass eine Domänenmitgliedschaft nötig ist.
# TODO Remoting auf Bediener-PC und Wartungs-Server aktivieren:
Get-NetAdapter -Physical | Set-NetConnectionProfile -NetworkCategory 'Private' -PassThru
Enable-PSRemoting -Force
Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value '*' -Force
# !TODO Auf dem Wartungs-Server bzw. AD-Domäne Nicht-Admin-Benutzer und -Gruppe festlegen / erstellen die Verwaltungsaufgaben erledigen müssen:
$NewUser = @{
Name = 'DruckerHorst'
AccountExpires = (Get-Date).AddHours(24)
Description = "24h Demo-Drucker-Managers ohne Admin-Rechte."
Password = (Read-Host -Prompt "Passwort für DruckerHorst" -AsSecureString)
PasswordNeverExpires = $true
UserMayNotChangePassword = $true
}
New-LocalUser @NewUser
New-LocalGroup -Name 'LocalPrinterManagerGroup' -Description 'JEA-Demo: DruckerManager-Gruppe für nicht Admins'
Add-LocalGroupMember -Group 'LocalPrinterManagerGroup' -Member 'DruckerHorst'
2. Module-Ordner erstellen
Den JEA-PowerShell-Module-Ordner auf dem Wartungsserver erstellen in dem später die Rollenfunktionsdateien (Role Capabilities) gesucht werden.
WICHTIG - Der folgende Modul-Ordner muss vor Manipulation geschützt werden, Stichwort ACL.
# Für PowerShell 7:
$ModulePath = "$env:ProgramFiles\PowerShell\Modules\AbcFirma"
# Für Windows PowerShell:
$ModulePath = "$env:ProgramFiles\WindowsPowerShell\Modules\AbcFirma"
New-Item -Path $ModulePath -ItemType 'Directory'
New-ModuleManifest -Path "$ModulePath\AbcFirma.psd1" -RootModule 'AbcFirma'
3. Rollenfunktions-Datei erstellen
In dieser/n Rollenfunktionsdatei(en) (PowerShell Role Capability File .PSRC
) legen Sie fest welche Rolle was auf dem Wartungs-Server machen darf.
New-Item -Path "$ModulePath\RoleCapabilities" -ItemType 'Directory'
$Parameter = @{
Path = "$ModulePath\RoleCapabilities\PrinterManagerRoleCapability.psrc"
Author = 'Attila Krick'
CompanyName = 'ATTILAKRICK.COM'
Description = 'Benötigte Tools für Drucker-Manager.'
ModulesToImport = 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Core', 'Microsoft.PowerShell.Utility'
VisibleProviders = 'FileSystem', 'Environment', 'Registry'
VisibleCmdlets = 'Clear-Host', 'Exit-PSSession', 'Get-Command', 'Get-ChildItem', 'Get-FormatData', 'Get-Help', 'Measure-Object', 'Out-Default', 'Out-String', 'Select-Object', `
@{ Name = 'Restart-Computer'; Parameters = @{ Name = 'ComputerName' ; ValidatePattern = 'VDI\d+' } }, `
@{ Name = 'Restart-Service' ; Parameters = @{ Name = 'Name' ; ValidateSet = 'Dns', 'Spooler' } }
FunctionDefinitions = @{ Name = 'Get-UserInfo' ; ScriptBlock = { $PSSenderInfo } }
VisibleExternalCommands = 'C:\Windows\System32\WhoAmI.exe'
}
New-PSRoleCapabilityFile @Parameter
# TODO Kontrolle:
Start-Process -FilePath "$ModulePath\RoleCapabilities\PrinterManagerRoleCapability.psrc"
Weitere Details finden Sie in der Microsoft Dokumentation Erstellen einer Rollenfunktionsdatei.
4. Sitzungskonfigurations-Datei erstellen
In dieser Sitzungskonfigurations-Datei (PowerShell Session Configuration File .PSSC
) wird die Nicht-Admin-Gruppe(n) mit der entsprechenden Rolle verknüpft.
New-Item -Path "$env:ProgramData\JEASessionConfigurations" -ItemType 'Directory'
$JEAConfigParams = @{
Path = "$env:ProgramData\JEASessionConfigurations\JEAPrintServerSession.pssc"
Author = 'Attila Krick'
Description = 'Verbindet die Rollen (u.a. Drucker-Manager) mit dieser Session (JEAPrintServerSession)'
CompanyName = 'ATTILAKRICK.COM'
SessionType = "Default" # ! PROBLEM: "RestrictedRemoteServer"
RunAsVirtualAccount = $true
TranscriptDirectory = "$env:ProgramData\JEASessionConfigurations\Transcripts"
RoleDefinitions = @{ 'LocalPrinterManagerGroup' = @{RoleCapabilities = 'PrinterManagerRoleCapability'}}
Full = $true
}
New-PSSessionConfigurationFile @JEAConfigParams
# ! Kontrolle:
Test-PSSessionConfigurationFile -Path "$env:ProgramData\JEASessionConfigurations\JEAPrintServerSession.pssc"
Start-Process -FilePath "$env:ProgramData\JEASessionConfigurations\JEAPrintServerSession.pssc"
Weitere Details finden Sie in der Microsoft Dokumentation JEA-Sitzungskonfigurationen sowie unter Get-Help -Name 'about_Session_Configuration_Files' -ShowWindow
.
5. Die Sitzungskonfiguration registrieren und etablieren
Jetzt können wir Sitzungskonfiguration registrieren und den Endpoint etablieren, um so JEA für den Bediener zu aktivieren.
Register-PSSessionConfiguration -Name 'JEAPrintServerSession' -Path "$env:ProgramData\JEASessionConfigurations\JEAPrintServerSession.pssc" -Force
Restart-Service WinRM
# ! Kontrolle - Übersicht der registrierten Sitzungskonfigurationen:
Get-PSSessionConfiguration | Select-Object Name, Permission
Weitere Details finden Sie in der Microsoft Dokumentation Registrieren von JEA-Konfigurationen.
6. Just Enough Administration als Bediener/Verwalter verwenden
Jetzt zeigt es sich, wie es um die PowerShell Sicherheit gestellt ist.
# TODO 1. Per Just Enough Administration (JEA) sich mit dem zu verwalten Server als Nicht-Admin per Remote verbinden:
$cred = Get-Credential -UserName 'DruckerHorst' -Message 'Credential für localhost'
# ! Administrator-Remote-Verbindung ist NICHT erlaubt:
Enter-PSSession -ComputerName 'localhost' -Credential $cred
# * JEA-Remote-Verbindung ist ERLAUBT:
Enter-PSSession -ComputerName 'localhost' -ConfigurationName 'JEAPrintServerSession' -Credential $cred
# ! 2. Eine Übersicht der Rechte für Benutzer X:
Get-PSSessionCapability -ConfigurationName "JEAPrintServerSession" -Username "DruckerHorst" -Full
# ! 3. Just Enough Administration testen:
C:\Windows\System32\WhoAmI.exe # * erlaubt
Get-ChildItem -Path Hkcu:\ # * erlaubt
Restart-Service -Name Spooler # * erlaubt
Restart-Service -Name AudioSrv # ! Nicht erlaubt
Restart-Computer -ComputerName localhost # ! Nicht erlaubt
Restart-Computer -ComputerName VDI009 # * erlaubt
Get-UserInfo # * erlaubt
Get-Command # * erlaubt
exit # * erlaubt
Weitere Details finden Sie in der Microsoft Dokumentation [Verwenden von JEA](https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/jea/register-jea).
7. Aufgezeigt Konfiguration zurücksetzen
Aufgezeigt Konfiguration wieder rückgängig machen und sämtliche Spuren beseitigen
Unregister-PSSessionConfiguration -Name 'JEAPrintServerSession'
Restart-Service -Name 'WinRM'
Remove-Item -Path "$env:ProgramData\JEASessionConfigurations\JEAPrintServerSession.pssc" -Force
Remove-Item -Path "$env:ProgramFiles\WindowsPowerShell\Modules\AbcFirma\RoleCapabilities\PrinterManagerRoleCapability.psrc" -Force
Remove-Item -Path "$env:ProgramFiles\WindowsPowerShell\Modules\AbcFirma\AbcFirma.psd1" -Force
Remove-Item -Path "$env:ProgramFiles\WindowsPowerShell\Modules\AbcFirma" -Recurse -Force
Remove-LocalGroup -Name 'LocalPrinterManagerGroup'
Remove-LocalUser -Name 'DruckerHorst'
Set-Item -Path "WSMan:\localhost\Client\TrustedHosts" -Value ([String]::Empty) -Force
Disable-PSRemoting -Force
Get-NetAdapter -Physical | Set-NetConnectionProfile -NetworkCategory 'Public'
PowerShell Sicherheit per GPO verteilen
PowerShell Sicherheit per GPO in der ActiveDirectory-Domäne verteilen.
EdgeUI.admx
User
/Windows Components
/Edge UI
/Prevent users from replacing the Command Prompt with Windows PowerShell in the menu they see when they right-click the lower-left corner or press the Windows logo key+X
- HKCU\Software\Policies\Microsoft\Windows\EdgeUI!ShowCommandPromptOnWinX
PowerShellExecutionPolicy.admx
Machine
/Windows Components
/Windows PowerShell
/Turn on PowerShell Script Block Logging
- HKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockLogging
- HKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockInvocationLogging
User
/Windows Components
/Windows PowerShell
/Turn on PowerShell Script Block Logging
- HKCU\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockLogging
- HKCU\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockInvocationLogging
Machine
/Windows Components
/Windows PowerShell
/Turn on PowerShell Transcription
- HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableTranscripting
- HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription!OutputDirectory
- HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableInvocationHeader
User
/Windows Components
/Windows PowerShell
/Turn on PowerShell Transcription
- HKCU\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableTranscripting
- HKCU\Software\Policies\Microsoft\Windows\PowerShell\Transcription!OutputDirectory
- HKCU\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableInvocationHeader
Epilog
Von mir gibt es noch weitere PowerShell-Fachartikel und Guides. Und jetzt Neu, abonnieren Sie meinen PowerShell-YouTube-Kanal.
Wissen vom Trainer mit praxisbezogenen Übungen, Wissenstests und Frage und Antwort-Runden. Jetzt in meinen PowerShell-Seminaren und -Workshops.
Bitte bewerten Sie diesen Artikel, wenn Sie diesen als hilfreich empfunden haben. Und teilen Sie diesen Artikel in den sozialen Medien. Als Dankeschön erhalten Sie ein von mir erstelltes hochwertiges A1-PowerShell-7-Poster mit den TOP wichtigsten Informationen für die tägliche Arbeit per Post zugesendet. Hierzu schreiben Sie mir an info at attilakrick.com einfache eine E-Mail mit dem Link der Erwähnung sowie Ihre Adresse. Aber nur solange der Vorrat reicht. Ihre Daten (E-Mail, Adresse) werden nur zum Zweck des Poster-Versandes benötigt und anschließend gelöscht.
[site_reviews_form category="121" assign_to="258" id="kcb17qh9" hide="title,content,name,email,terms"]