Private/Wissen/C_Advance/C11_Sicherheit.ps1
<#
# Sicherheit PowerShell absichern und mit Sicherheit in der PowerShell umgehen - **Hashtags** Sicherheit Security PKI NTFS Security Crypt Decrypt Signature Credentials ActiveDirectory GPO ScriptBlockLogging Transcript CLM PSRC PSSC - **Version** 2020.05.13 #> # ! EINLEITUNG: Die PowerShell ist im System verwurzelt. Daher sorgt ein generelles Blockieren nur für scheinbare Sicherheit. Den besten Schutz versprechen letztlich die **Schutzmechanismen von PowerShell** selbst. Neben Mitteln, die den Missbrauch von PowerShell unterbinden, stehen auch solche zur Verfügung, um verdächtigen und unerwünschten Aktivitäten zu **protokollieren** und diese auf die Spur zu kommen. #region TEIL A :: Sicherheit IN der PowerShell #region Strings # ! Grundsätzlich immer die einfachen Hochkommas ' verwenden, es seiden man verwendet Variablen. Erst dann die doppelten Hochkommas " verwenden. $ort = 'Würzburg' $s = 'Hallo $ort!' $s = "Hallo $ort!" #endregion #region Für Initial-Passwörter (z.B. beim Zurücksetzen / Neu-Anlage) generieren # ! Möglichkeit 1: [System.IO.Path]::GetRandomFileName() -replace "\.", [String]::Empty | Write-Warning # ! Möglichkeit 2: (1..100 | Get-Random -Count 3 | ForEach-Object { "{0:00}" -f $_ }) -join [String]::Empty | Write-Warning # ! Möglichkeit 3: [Convert]::ToBase64String((0..255 | Get-Random -Count 9)) | Write-Warning # TODO z.B. praktische Anwendung: 'p.mueller', 'i.schmitt', 'k.bauer', 'e.baecker' | ConvertFrom-Csv -Header 'Username' | ForEach-Object -Process { $_ | Add-Member -Name 'PlainTextPassword' -Value ([Convert]::ToBase64String((0..255 | Get-Random -Count 9))) -MemberType NoteProperty $_ | Add-Member -Name 'Password' -Value ($_.PlainTextPassword | ConvertTo-SecureString -AsPlainText -Force) -MemberType NoteProperty return $_ } #endregion #region SecureString # ? Ein Passwort verschlüsselt aufbewarben und sicher wieder einlesen: # ! Muss jedoch für jeden PC und Benutzter erneut generiert werden. # ? 1. Passwort sicher abfragen und verschlüsselt auf C:\ speichern: Read-Host -Prompt "Passwort eingeben" -AsSecureString | ConvertFrom-SecureString | Out-File -FilePath "C:\temp\SecureString.txt" -Force Get-ChildItem -Path "C:\Temp\SecureString.txt" | Get-Content | Write-Warning # ! 2. Verschlüsselt Passwort von C:\ wieder einlesen: Get-Content -Path "C:\Temp\SecureString.txt" | ConvertTo-SecureString | Write-Warning # TODO Aufräumen: Remove-Item -Path "C:\Temp\SecureString.txt" -Force #endregion #region Credentials # ! Unterschiedliche Cmdlets erwarten über einen Parameter Authentifizierungsinformationen (Benutzname & Passwort) in Form eines [PSCredential]-Objektes. Dieses [PSCredential]-Objekt kann per Cmdlet Get-Credential oder manuell erzeugt werden. Der Fokus liegt hierbei auf das Password das als SecureString-Objekt verschlüsselt im Arbeitsspeicher abgelegt ist: $cred = Get-Credential -Message "Zugangsdaten für Administrator auf 127.0.0.1" -UserName "Administrator" Enter-PSSession -ComputerName "127.0.0.1" -Credential $cred # ! Credentials können auch verschlüsselt im Dateisystem gespeichert werden um diese später wieder einzulesen: # ! 1. verschlüsselt speichern: $username = Read-Host -Prompt "Benutzername eingaben" $password = Read-Host -Prompt "Passwort für $username eingeben" -AsSecureString [PSCustomObject]@{ Username = $username Password = $password | ConvertFrom-SecureString } | ConvertTo-Json | Set-Content -Path "C:\Temp\Credential_Admin.json" -Force # ! 2. Verschlüsselte Daten laden, und daraus ein Credential-Objekt Instanziieren: $admin = Get-Content -Path C:\Temp\Credential_Admin.json | ConvertFrom-Json | Select-Object Username, @{Label="Password"; Expression={$_.Password | ConvertTo-SecureString}} $cred = [System.Management.Automation.PSCredential]::new($admin.Username, $admin.Password) $cred Enter-PSSession -ComputerName "127.0.0.1" -Credential $cred # TODO Aufräumen: Remove-Item -Path "C:\Temp\Credential_Admin.json" -Force #endregion #region Zeichenketten verschlüsseln # READ betroffene Cmdlets: Get-Command -Noun "CmsMessage" -Module "Microsoft.PowerShell.Security" # READ CipherNet Lite => Funktionsbibliothek zum Thema Verschlüsselung # ! 1. Vorbereitung: using namespace "Microsoft.CertificateServices.Commands" $params = @{ FriendlyName = "Superman" Subject = "CN=_Superman (Doctor S. Man), E=s.man@krypton.universe" HashAlgorithm = "SHA512" KeyExportPolicy = [KeyExportPolicy]::ExportableEncrypted KeyLength = 4096 KeySpec = [KeySpec]::KeyExchange CertStoreLocation = "Cert:\CurrentUser\My" Type = [CertificateType]::DocumentEncryptionCert NotAfter = (Get-Date).AddMinutes(60) } $myPfxCert = New-SelfSignedCertificate @params # ! 2. Verschlüsseln: $cryptedText = "Hallo Würzburg!" | Protect-CmsMessage -To $myPfxCert.Thumbprint # ! 3. Chiffre checken: $cryptedText | Get-CmsMessage # ! 4. Entschlüsseln $cryptedText | Unprotect-CmsMessage -To $myPfxCert.Thumbprint | Write-Warning # TODO Aufräumen: Get-ChildItem -Path "Cert:\CurrentUser\My" | Where-Object -Property "Subject" -CLike -Value "CN=_Superman (Doctor S. Man), E=s.man@krypton.universe" | Remove-Item -Force #endregion #region Credentials sicher persistent speichern # ! 'Microsoft.PowerShell.SecretManagement'-Module installieren: Find-Module -Name 'Microsoft.PowerShell.SecretManagement' -Repository "PSGallery-Alternative" -AllowPrerelease | Install-Module -Scope "CurrentUser" -SkipPublisherCheck -AllowPrerelease -Force # ! Credential persistent speichern: Set-Secret -Name "Administrator" -Secret (Get-Credential) -Vault "BuiltInLocalVault" # ! Credential abrufen und verwenden: $Credential = Get-Secret -Name "Administrator" -Vault "BuiltInLocalVault" Start-Process -FilePath 'notepad.exe' -Credential $Credential Get-Process 'notepad' -IncludeUserName # TODO Aufräumen: Get-Process 'notepad' | Stop-Process -Force Remove-Secret -Name "Administrator" -Vault "BuiltInLocalVault" Remove-Module -Name "Microsoft.PowerShell.SecretManagement" -Force Uninstall-Module -Name "Microsoft.PowerShell.SecretManagement" -AllVersions -AllowPrerelease -Force #endregion #region Skripte die Admin-Berechtigungen benötigen # ! WICHTIG :: Skripte die erhöhte Admin-Berechtigungen benötigen, immer zu beginn prüfen ob diese vorliegen. Wenn nicht is es immer besser das Skript bricht zu beginn ab, als mitten drin. $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 } #endregion #region PKI # 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 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 # ! ODER über den Cert-Speicher: 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 #endregion #region Umgang mit Zugriffsberechtigungen # ! Die PowerShell-Board-Mittel sind leider noch überschaubar: Get-Command -Name "Get-Acl", "Set-Acl", "ConvertFrom-SddlString" # ? Berechtigungen von Ordner-A auf Ordner-B übetragen: 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" # ? Berechtigungen von ACL-Objekte 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 Module NtfsSecurity aus der PowerShallGallery 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 Remove-Item -Path "C:\TempTest" -Recurse -Force #endregion #endregion #region TEIL B :: Sicherheit AN der PowerShell # READ Vergleich Sicherheitsmechanismen div. Script-Sprachen https://devblogs.microsoft.com/powershell/a-comparison-of-shell-and-scripting-language-security/ #region Windows PowerShell 2 # !!! UNBEDINGT sollten Sie PowerShell 2.0 ENTFERNEN. 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. !!! #endregion #region Ausführungsrichtlinien konfigurieren # ! ACHTUNG :: 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: Set-ExecutionPolicy -ExecutionPolicy "AllSigned" -Force # ! D.h.: Alle ausführbare Dateien müssen mit einem x.509-Zertifikat signiert sein! # ? Empfohlene Einstellung für Test-/Entwicklungszwecke: Set-ExecutionPolicy -ExecutionPolicy 'RemoteSigned' -Force # ! D.h.: Alle ausführbare Dateien müssen mit einem x.509-Zertifikat signiert sein, die Remote (Download, UNC, etc.) auf den PC gelangt sind. Diese werden Dateien an einem 'Download-Marker' identifiziert der mit dem Cmdlet 'Unblock-File' wieder entfernt werden kann. # TODO :: Für das automatische Ausführen von signierten Skripten müssen folgende Voraussetzungen erfüllt sein: 1. Das X.509-Zertifikat muss von einer "Vertrauenswürdigen Stammzertifizierungsstelle" (Root) abstammt ODER es ist selbst in Root abgelegt! Und 2. das X.509-Zertifikat muss im Zertifikatspeicher für "Vertrauenswürdige Herausgeber" (TrustPublisher) enthalten ist. # TODO :: 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\1\ShellIds\Microsoft.PowerShell" -Name "ExecutionPolicy" Get-ItemPropertyValue -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\ScriptedDiagnostics" -Name "ExecutionPolicy" Get-ItemPropertyValue -Path "Registry::HKEY_CURRENT_USER\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" -Name "ExecutionPolicy" #endregion #region PowerShell-Scripte (.PS1, .PSM1, ...) signieren # TODO :: Für das automatische Ausführen von signierten Skripten müssen folgende Voraussetzungen erfüllt sein: 1. Das X.509-Zertifikat muss von einer "Vertrauenswürdigen Stammzertifizierungsstelle" (Root) abstammt ODER es ist selbst in Root abgelegt! Und 2. das X.509-Zertifikat muss im Zertifikatspeicher für "Vertrauenswürdige Herausgeber" (TrustPublisher) enthalten ist. Import-WinModule -Name 'PKI' Import-Certificate -FilePath '.\Z_Superman.cer' -CertStoreLocation "Cert:\LocalMachine\Root" Import-Certificate -FilePath '.\Z_Superman.cer' -CertStoreLocation "Cert:\LocalMachine\TrustedPublisher" # TODO Test-Umgebung erzeugen: Set-ExecutionPolicy -ExecutionPolicy "AllSigned" -Scope "Process" "' > > > The Power of PowerShell-Power < < < ' | Write-Warning" | Set-Content -Path "C:\Temp\Superman_Test.ps1" -Force & 'C:\Temp\Superman_Test.ps1' # TODO .PS1-Datei signieren: $params = @{ Certificate = (Get-PfxCertificate -FilePath '.\Z_Superman.pfx') # Password: P@ssw0rd FilePath = 'C:\Temp\Superman_Test.ps1' Force = $true IncludeChain = 'all' HashAlgorithm = 'SHA512' TimestampServer = 'http://timestamp.globalsign.com/scripts/timstamp.dll' } Set-AuthenticodeSignature @params # TODO Signierte Datei validieren: 'C:\Temp\Superman_Test.ps1' | Get-AuthenticodeSignature | Select-Object -Property * & 'C:\Temp\Superman_Test.ps1' # TODO Aufräumen: Set-ExecutionPolicy -ExecutionPolicy 'RemoteSigned' -Scope 'Process' -Force Get-ChildItem -Path 'Cert:\LocalMachine\', 'Cert:\CurrentUser\' -Recurse | Where-Object -Property 'Thumbprint' -CEQ -Value '76607F936AB133FEA29630B2843FE3B3EBE5F41F' | Remove-Item -Force Get-ChildItem -Path 'C:\temp\Superman_Test.ps1' | Remove-Item -Force #endregion #region Permanentes und sicheres Protokollieren sämtlicher Host's aktivieren (ScriptBlockLogging) # TODO Betrifft 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 Script aus: . "$PsHome\RegisterManifest.ps1" Get-WinEvent -ListProvider *powershell* | Select-Object -Property Name # TODO per GP aktivieren unter: Computerkonfiguration / Administrative Vorlagen / Windows-Komponenten / Windows PowerShell / Protokollierung von PowerShell-Scriptblöcken aktivieren. ACHTUNG z.Zt. nur für Windows PowerShell, andere Versionen nur per Registry-Key. # ! 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 # TODO Windows Log auswerten: # Test-Code: Get-ChildItem -Path 'C:\Temp' 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 Um sensible Daten zu schützen sollten diese Log's verschlüsselt werden (s. Protected Event Logging): Get-Help -Name "about_logging_windows" -ShowWindow # 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 #endregion #region Eine PowerShell-Session einschränken (RestrictedLanguage) # READ siehe auch: Get-Help -Name "about_RestrictedLanguage" -ShowWindow Get-Help -Name "about_FullLanguage" -ShowWindow Get-Help -Name "about_Language_Modes" -ShowWindow # ! z.B. 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. In den beschränkten Sprachmodus wechseln: $ExecutionContext.SessionState.LanguageMode = "RestrictedLanguage" #endregion #region Aktivieren des eingeschränkten PowerShell-Sprachmodus (Constrained Language Mode (CLM)) # ! Zu den wichtigsten Sicherheitsmechanismen gehört der 'Constrained Language Mode' der mehrere gefährliche PowerShell-Features deaktiviert und so deren Missbrauch minimiert. # READ Get-Help -Name "about_ConstrainedLanguage" -ShowWindow # ? Eine automatische Erkennung einer Ausführungsbeschränkung (Constrained Language Mode) aktivieren: # 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 Sprachmodus. Dazu müssen Sie lediglich das Ausführen von Skripten im Ordner $env:TEMP verbieten. # TODO ... Realisieren können Sie das 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 #endregion #region PowerShell-Remoting absichern und trotzdem Admin-Aufgaben an Nicht-Admins delegieren mit Just Enough Administration (JEA) # TODO Nötig für PowerShell 7: Import-WinModule -Name 'NetAdapter' Import-WinModule -Name 'NetConnection' Import-WinModule -Name 'Microsoft.PowerShell.LocalAccounts' #region 1. Voraussetzungen prüfen # READ Voraussetzungen: https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/jea/prerequisites?view=powershell-7 # ? 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 } #endregion #region 2. Vorbereitungen treffen # 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' #endregion #region 3. Module-Ordner erstellen # TODO Den JEA-PowerShell-Module-Ordner auf dem Wartungsserver erstellen in dem später die Rollenfunktionsdateien (Role Capabilities) gesucht werden: # ! WICHTIG :: Den folgenden Module-Ordner muss vor Manipulation geschützt werden (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' #endregion #region 4. Rollenfunktions-Datei erstellen # READ JEA-Rollenfunktionen https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/jea/role-capabilities?view=powershell-7#create-a-role-capability-file # TODO 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" #endregion #region 5. Sitzungskonfigurations-Datei erstellen # READ: Get-Help -Name "about_Session_Configuration_Files" -ShowWindow # READ JEA-Sitzungskonfigurationen https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/jea/session-configurations?view=powershell-7 # TODO 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" #endregion #region 6. Die Sitzungskonfiguration registrieren und etablieren # READ Registrieren von JEA-Konfigurationen https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/jea/register-jea?view=powershell-7 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 #endregion #region 7. JEA als Bediener/Verwalter verwenden # READ Verwenden von JEA https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/jea/using-jea?view=powershell-7 # TODO 1. Per 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. JEA 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 #endregion #region 8. 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\PowerShell\Modules\AbcFirma" -Recurse -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" #endregion #endregion #region PowerShell per GPO in der ActiveDirectory-Domäne absichern <# ! EdgeUI.admx ? 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 User - Windows Components\Edge UI HKCU\Software\Policies\Microsoft\Windows\EdgeUI!ShowCommandPromptOnWinX ! PowerShellExecutionPolicy.admx ? Turn on PowerShell Script Block Logging Machine - Windows Components\Windows PowerShell HKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockLogging HKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockInvocationLogging ? Turn on PowerShell Script Block Logging User - Windows Components\Windows PowerShell HKCU\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockLogging HKCU\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging!EnableScriptBlockInvocationLogging ? Turn on PowerShell Transcription Machine - Windows Components\Windows PowerShell HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableTranscripting HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription!OutputDirectory HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableInvocationHeader ? Turn on PowerShell Transcription User - Windows Components\Windows PowerShell HKCU\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableTranscripting HKCU\Software\Policies\Microsoft\Windows\PowerShell\Transcription!OutputDirectory HKCU\Software\Policies\Microsoft\Windows\PowerShell\Transcription!EnableInvocationHeader #> #endregion #endregion |