Spaß mit Kennwörtern und Anmeldeinformation in der Windows PowerShell

Ein recht häufig auftretendes Szenario im alltäglichen Umgang mit der Microsoft PowerShell ist die korrekte Übergabe von Kennwörtern oder gar kompletter Anmeldeinformation im Format Benutzername und Kennwort. Dazu halten einige PowerShell Cmdlets direkt verschiedene Parameter vor, beispielsweise ‚Password‘, ‚AccountPassword‘ oder ‚Credential‘.

Problematisch ist oftmals die Situation, dass diese Werte sowohl in der Shell-Sitzung oder auch im Skripting-Umfeld direkt im Klartext übergeben werden. Einerseits erwarten die meisten Cmdlets die Eingabe des Kennworts im Format ‚System.Security.SecureString‘, andrerseits ist es unter Sicherheitsaspekten nicht unbedenklich, wenn Kennwortinformationen im Klartext eingegeben oder in einer Skriptdatei gespeichert werden.

Daher hier einige Ideen, wie Sicherheitsinformationen in verschiedenen Formaten geschützt an der PowerShell übergeben werden können…

Übergabe von Kennwörtern

Die direkte Übergabe von Kennwörtern kommt in verschiedenen Szenarien im PowerShell-Alltag vor. In diesem Beispiel verwende ich die Active Directory-Cmdlets ‚Get-ADUser‘ und ‚Set-ADAccountPassword‘ des Moduls ‚ActiveDirectory‘, um das Kennwort eines einzelnen oder alternativ mehrerer Benutzer zu ändern. Die Syntax sieht dabei wie folgt aus:

Get-ADUser -Identity <Benutzername> | Set-ADAccountPassword -NewPassword <Kennwort> -Reset

Get-ADUser -Filter { <Filtereigenschaft> } | Set-ADAccountPassword -NewPassword <Kennwort> -Reset

Alternativ lässt sich in diesem Fall auch ausschließlich das Cmdlet ‚Set-ADAccountPassword‘ mit dem Parameter ‚Identity‘ verwenden.

Auf geht’s…

Zunächst ein recht häufiges Fehlerszenario, bei dem das Kennwort über den Parameter ‚AccountPassword‘ als Klartextwert übergeben wird:

Get-ADUser -Identity test | Set-ADAccountPassword -NewPassword 'Pa$$w0rd' -Reset
credential1
Unzulässige Übergabe des Paramter NewPassword im Klartext

Der Versuch das Kennwort des Benutzers Test zurückzusetzen schlägt in diesem Kontext fehl, da – wie die Fehlermeldung suggeriert – für den Parameter ‚New-Password‘ der Wert im Format ‚System.String‘ übergeben wurde. Hier wurde allerdings seitens des Cmdlets das Format ‚System.Security.SecureString‘ erwartet.

Im nächsten Versuch soll nun der Parameter ‚New-Password‘ das richtige Format aufweisen. Dazu kommt das Cmdlet ‚ConvertTo-SecureString‘ zum Einsatz:

Get-ADUser -Identity test | Set-ADAccountPassword -NewPassword (ConvertTo-SecureString -String 'Pa$$w0rd' -AsPlainText -Force) -Reset
credential2
Umwandlung des Kennwort in das Format System.Security.SecureString – Variante 1

In diesem Fall ist die Aktion erfolgreich, da zunächst das Cmdlet ‚ConvertTo-SecureString‘ – bedingt durch die Klammersetzung – den Klartextwert ‚Pa$$w0rd‘ in das richtige Format wandelt. Allerdings braucht auch dieses Cmdlet einen erweiterten Anreiz einen Klartextwert zu akzeptieren, wie die weiteren Parameter ‚AsPlainText‘ und ‚Force‘ belegen. Im Standardfall wird durch das Cmdlet direkt der passende sichere Hashwert erwartet, der dann entsprechend umgewandelt werden kann.

Im Hinblick auf die Verwendung der Klammersetzung stellt sich allerdings auch die Frage der Lesbarkeit der Pipeline. Alternativ könnte die Verwendung einer Variable diese Situation verbessern:

$password = ConvertTo-SecureString -String 'Pa$$w0rd' -AsPlainText -Force

Get-ADUser -Identity test | Set-ADAccountPassword -NewPassword $password -Reset
credential3
Umwandlung des Kennwort in das Format System.Security.SecureString – Variante 2

Im Endeffekt wird hier das gleiche Ziel erreicht, allerdings nun mit einer eher suk­zes­siven Schreibweise.

Nachteilig in beiden vorangegangenen Szenarien bleibt jedoch der Fakt, das der String ‚Pa$$word‘ im Klartext zu lesen ist. Um dies zu vermeiden ergeben sich wiederum mehrere Möglichkeiten, u.a. in Abhängigkeit, inwieweit die ausführende Person das Kennwort im Klartext kennen darf.

Darf das Kennwort nicht im Klartext erscheinen, soll dieses jedoch zur Ausführungszeit übergeben werden, bietet sich das Cmdlet ‚Read-Host‘ an:

$password = Read-Host -Prompt 'Kennwort' -AsSecureString

Get-ADUser -Identity test | Set-ADAccountPassword -NewPassword $password -Reset
credential4
Sichere Kennwortübergabe durch geschützte Eingabe

Hier muss das Kennwort im Klartext bekannt sein, wird jedoch in gesicherter Form abgefragt. Das Kennwort ist zu keiner Zeit im Klartext sichtbar und kann nachträglich auch nicht mehr zurück konvertiert werden.

Darf das Kennwort darüber hinaus nicht einmal im Klartext bekannt sein, oder soll es zur Ausführungszeit nicht eingegeben werden, z.B. bei einer automatischen und unbeaufsichtigten Ausführung eines Skripts, bleibt noch, das Kennwort direkt als geschützten Wert zu übergeben.

Dazu können in Kombination die Cmdlets ‚ConvertTo-SecureString‘ und ‚ConvertFrom-SecureString‘ verwendet werden, um das gesicherte Kennwort in Dateiform zur Verfügung zu stellen:

Vorbereitung:

ConvertTo-SecureString -String 'Pa$$w0rd' -AsPlainText -Force | ConvertFrom-SecureString | Out-File -FilePath C:\Temp\password.txt
credential5
Sichere Kennwortübergabe durch gespeicherten Hashwert – Vorbereitung

Das Klartextkennwort wird zunächst intern in das Format ‚System.Security.SecureString‘ gewandelt und anschließend als Hashwert extrahiert. Dieser wird nun in die Datei ‚password.txt‘ gespeichert. Das Cmdlet ‚Get-Content‘ zeigt den Inhalt der Datei an und ist hier nur zu Demonstrationszwecken angeführt.

Ausführung:

$password = Get-Content -Path C:\Temp\password.txt | ConvertTo-SecureString

Get-ADUser -Identity test | Set-ADAccountPassword -NewPassword $password -Reset
credential6
Sichere Kennwortübergabe durch gespeicherten Hashwert – Ausführung

Nun wird in die Variable ‚password‘ der Inhalt der Datei ‚password.txt‘ geladen und wieder in das Format ‚System.Security.SecureString‘ gewandelt. Somit ist im Rahmen der Ausführung weder das Klartextkennwort bekannt, noch ist es in diesem Abschnitt im Klartext lesbar. Bleibt die Frage nach der Sicherheit des gesicherten Kennworts selbst: Auch die Datei ‚password.txt‘ muss in diesem Kontext gesichert übergeben werden, was aber Schutzmechanismen außerhalb des PowerShell-Bereichs notwendig macht, z.B. NTFS-Berechtigungen, Laufwerk mit Bitlocker-Verschlüsselung, etc.

Übergabe von Anmeldeinformationen

Ist für die Funktion einer PowerShell-Pipeline die erweiterte Übergabe von Anmeldeinformationen notwendig, geschieht dies meist durch einen Parameter ‚Credential‘. Dieser erwartet dann eine Wertekombination aus Benutzernamen im Format ‚System.String‘ und eines Kennworts im Format ‚System.Security.SecureString‘.

Als Beispiel verwende ich eine Remotesitzung mit einem Domänencontroller, welche es mir ermöglich per implizitem Remoting das Modul ‚ActiveDirectory‘ lokal auf meiner Windows 10 Workstation zu laden. Die lokale PowerShell wird zur Demonstration nur mit lokalen Benutzerrechten und nicht administrativ gestartet:

$session = New-PSSession -ComputerName <Zielcomputer> -Name <Sitzungsname> -Credential <Anmeldeinformationen>

Import-Module -Name 'ActiveDirectory' -PSSession $session

Im folgenden der praktische Verlauf:

credential7
Übergabe von Anmeldeinformationen

Der erste Versuch das Modul ‚ActiveDirectory‘ zu laden schlägt fehl, da dieses lokal der Workstation nicht zur Verfügung steht.

Die Variable ’session‘ dient nun als Platzhalter für eine neue Remotingsitzung mit einem Domänencontroller, die durch das Cmdlet ‚New-PSSession‘ aufgebaut wird. Der Parameter ‚Credential‘ übergibt dabei den Benutzernamen für die serverseitige Authentifizierung. Zur Ausführung der Pipeline fordert die PowerShell nun das Kennwort für diesen Benutzer ein:

credential8
Kennwortabfrage

Anschließend ist die Sitzung nach erfolgreicher Authentifizierung aufgebaut und kann für explizites oder implizites Remoting verwendet werden. Während bei einem explizitem Remoting – ähnlich wie bei Telnet oder SSH – ein direktes interaktives Arbeiten auf dem Zielsystem möglich ist, wird bei einem implizitem Remoting die Schnittstelle nur als Dienstleister für lokale Erweiterungen verwendet.

Der erneute Import des Moduls ‚ActiveDirectory‘ unter Verwendung des Parameters ‚PSSession‘ ist jetzt erfolgreich, da die Modulinformationen im Kontext der Remotesitzung temporär in die lokale PowerShell-Sitzung geladen werden. In dieser Sitzung können nun die Cmdlets des Moduls ‚ActiveDirectory‘ verwendet werden z.B. ‚Get-ADUser‘.

Dieser Vorgang kann nun im Hinblick auf die Übergabe der Anmeldeinformationen weiter verfeinert werden. So lässt sich zunächst die Anmeldeinformation aus der bestehenden Pipeline lösen und über eine Variable ‚cred‘ übergeben. Das Cmdlet ‚Get-Credential‘ kann hierbei hilfreich sein:

$cred = Get-Credential -Credential <Anmeldeinformation>

$session = New-PSSession -ComputerName <Zielcomputer> -Name <Sitzungsname> -Credential $cred

Import-Module -Name 'ActiveDirectory' -PSSession $session

Die Übergabe der Anmeldeinformationen sieht dabei wie folgt aus:

credential9
Interaktive Übergabe von Benutzername und Kennwort

Zunächst wird in der Variable ‚cred‘ mit Hilfe des Cmdlet ‚Get-Credential‘ eine Anmeldeinformation im Format Benutzername (Typ: System.String) und Kennwort (Typ: System.Security.SecureString) gespeichert. In der Ausführung ist es über den Parameter ‚Credential‘ optional möglich einen Benutzernamen direkt zu übergeben.

Der Vorteil dieser Methode im Vergleich zur direkten Übergabe der Anmeldeinformationen an den Parameter ‚Credential‘ liegt in deren Wiederverwertbarkeit. So kann die Variable ‚cred‘ innerhalb der PowerShell-Sitzung beliebig oft für Anmeldevorgänge verwendet werden. Allerdings muss in dieser Situation das Kennwort zur Laufzeit übergeben werden und somit der ausführenden Person bekannt sein. Das Cmdlet ‚Get-Credential‘ besitzt nur einen Parameter ‚Credential‘ zur Übergabe eines Benutzernamen, jedoch keinen Parameter zur direkten Übergabe des Kennworts.

Soll im Rahmen der Anmeldeinformationen weder ein Wert für einen Benutzernamen noch für ein Kennwort übergeben werden, lohnt sich ein genauerer Blick auf die soeben erstellte Variable ‚cred‘:

$cred | Get-Member

Hierbei zeigt sich auch die genaue Typbezeichnung der Anmeldeinformationen, die in der PowerShell ‚System.Management.Automation.PSCredential‘ lautet. Dieser Objekttyp lässt sich in der PowerShell direkt mit Hilfe des Cmdlet ‚New-Object‘ erstellen:

$username = 'TIGGES\Administrator'

$password = ConvertTo-SecureString -String 'Pa$$w0rd' -AsPlainText -Force

$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$Password

Zunächst wird in der Variable ‚username‘ der Benutzername und in der Variable ‚password‘ das Kennwort als jeweiliger Wert hinterlegt. Dabei können für die Kennwortübergabe die bereits zu Beginn erwähnten Methoden allesamt verwendet werden. Anschließend wird über das Cmdlet ‚New-Object‘ ein Objekt des gewünschten Typs erstellt und mit Hilfe des Parameters ‚ArgumentList‘ die für diesen Objekttyp notwendigen Werte Benutzername (System.String) und Kennwort (System.Security.SecureString) im richtigen Format übergeben.

credential10
Automatische Übergabe von Benutzername und Kennwort

Somit ließe sich dann eine komplette Anmeldeinformation im Skriptverlauf hinterlegen, ohne interaktive Eingaben während der Skriptausführung zu provozieren.

 

Eine Antwort auf „Spaß mit Kennwörtern und Anmeldeinformation in der Windows PowerShell“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.