PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Die Powershell ist ein mächtiges, administratives Werkzeug. Viele Tätigkeiten lassen sich automatisieren. Fast alle Bereiche der Microsoft-Produkte lassen sich so steuern. Und die Powershell ist nativ mit an Bord. Jedes moderne Betriebssystem hat sie dabei.

Da ist es nur natürlich, dass auch unsere Hacker-Kollegen seit Langem einen Gefallen an dieser Plattform gefunden haben. Es existieren etliche Schadcodes für eine Vielzahl von Angriffen…

Doch auch Microsoft hat nicht (mehr) geschlafen! In der aktuellen PowerShell-Version gibt es einige interessante Schutzmechanismen. Diese möchte ich in einer Serie einmal vorstellen.

Voraussetzungen

Für einige der neuen Schutzmöglichkeiten wird die PowerShell-Version 5 benötigt. Diese gehört zu Windows 10 und Windows Server 2016 standardmäßig zur Grundausstattung. Auf älteren Systemen kann die PowerShell natürlich aktualisiert werden. Davon halte ich persönlich nicht viel, denn zu oft habe ich danach Probleme auf Clients und Servern beobachten dürfen. Aber auch für diese Systeme gibt es ein paar Einstellungsmöglichkeiten.

Generell halte ich es nicht für sinnvoll, die PowerShell einfach zu deaktivieren bzw. zu blockieren. Sie ist so tief im System verankert, dass ein geübter Angreifer es dennoch schaffen wird, auf einen PS-Prozess zuzugreifen. Und zudem ist sie für das Daily-Business einfach zu wertvoll!

Für die Angriffe habe ich eines meiner PSHacking-Scripte ausgewählt.

Und um einen Enterprise-Charakter darzustellen werde ich die Konfiguration natürlich über Gruppenrichtlinien vornehmen. Dazu steht in meiner LAB-Umgebung ein kleiner DomainController bereit.

mögliche Angriffsszenarien

Die Szenarien sind extrem vielfältig. Da die PowerShell auch auf das gesamte .net-Framework und alle WMI-Repositories zugreifen kann ist hier der Fantasie kaum eine Grenze gesetzt. Einige interessante Beispiele kommen gleich in meinen Szenarien vor.

In meinem Beispiel verwende ich einen Code, mit dem die Internet-Explorer-Passworte aus dem Credential-Manager ausgelesen werden. Das funktioniert für Benutzer mit und ohne administrative Berechtigungen und der Code ist nicht besonders lang:

$ClassLoader   = [Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
$PasswordVault = new-object Windows.Security.Credentials.PasswordVault
$PasswordVault.RetrieveAll() | 
    ForEach-Object { $_.RetrievePassword() ; $_ } | 
        Select-Object -Property Resource, UserName, Password | 
            Sort-Object Resource | 
                Format-Table -AutoSize

Es ist also ideal für eine Demonstration. Die erforderliche Klasse existiert aber erst seit Windows 8.x. Daher wird das auf Windows 7 nicht funktionieren. Egal, denn ich verwende ein aktuelles Windows 10.

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Szenario – PowerShell Constrained Language Mode

Angriff ohne Schutz

Die PowerShell kann nahezu auf alle Ressourcen und Werkzeuge des Betriebssystems zugreifen. Selbst wenn es keine passenden cmdlets gibt, kann mit .net-Unterstützung oder über die WMI fast jede Hürde überwunden werden.

Für alltägliche Aufgaben genügen meist die eingebauten cmdlets. Warum soll man daher die Erweiterungen zulassen? Genau das lässt sich mit dem LanguageMode definieren. Aktuell werden 2 Modi unterschieden

  • im FullLanguageMode ist alles erlaubt
  • im ConstrainedMode sind nur Basisbefehle möglich (mehr dazu findet ihr weiter unten). Dieser Mode wird auch als PSLockDown bezeichnet.

Der aktuelle Mode lässt sich recht einfach mit dieser Zeile abfragen:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Im Standard-Modus FullLanguage gibt es keine Einschränkung. Ein Angreifer kann daher z.B. .net-Konstrukte verwenden, um an seine Beute zu gelangen:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Konfiguration der Schutzkomponente

Die Aktivierung kann über eine Systemvariable erfolgen. Diese muss __PSLockdownPolicy heißen und den Wert 4 für den ConstrainedMode aufweisen. Der Wert 1 oder das Fehlen der Variable schaltet die PowerShell wieder in den FullLanguageMode.

Das Erstellen der Variable geht natürlich auch mit der PowerShell:

New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" -Name __PSLockdownPolicy -Value '4'

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Danach ist jede neue Powershell limitiert:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Das ist aber wie ein set-executionpolicy zu bewerten: wer die erforderlichen Rechte hat kann sich einfach darüber hinwegsetzen:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Daher – und auch wegen der zentralen Konfiguration – ist der Einsatz einer GPO sinnvoller. Hier kann man ebenfalls Systemvariablen erstellen:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Nur leider ist der Teil mit den Environment-Variablen in den Preferences zuhause: auch diese kann ein Administrator (wenn auch mit meinem Replace nur bis zum nächsten gpupdate) überschreiben:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Aber dafür benötigt man eben auch administrative Rechte: ein Standardbenutzer kann sich da nicht mehr rauswinden:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Ich weiß nicht, wie es euch dabei geht, aber mir missfällt diese Lösung. Abgesehen davon wäre dann auch eine unterschiedliche Mode-Konfiguration wünschenswert: für normale Benutzer der ConstrainedMode und für Admins der FullLanguage-Mode.

Genau das liefert der ConstrainedMode mit Applocker! Mit aktiviertem und konfigurierten Applocker wird die Anwendung des ConstainedModes für Standardbenutzer erzwungen. Und das kann mit einer einfachen GPO konfiguriert werden:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Bitte vergesst aber nicht, dass der Applocker-Dienst mitgestartet werden muss:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Ebenso wird für den Applocker ein Windows Client in der Enterprise-Edition benötigt. Nach einem gpupdate und ein/zwei Neustarts greift das Regelwerk. Fragt nun ein Standardbenutzer den Language-Mode ab, sieht er den eingeschränkten Modus. Ein Admin hingegen ist im FullLanguage-Mode unterwegs! Und das auch ohne die Systemvariable!

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Angriff eines geschützten Systems

Aber wie schützt der Constrained Mode nun eigentlich? Eigentlich recht simpel: es werden entliche für Angreifer interessante Technologien abgeschaltet. Statt den Passwörtern bekommt dieser Angreifer nur Fehlermeldungen. Die erste kennzeichnet die Einschränkung des Sprachmodus. Der zweite Fehler ist daher nur ein Folgefehler.

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Egal: ein Ergebnis gibt es nicht mehr!

Nebenwirkungen und nützliche Hinweise

Auch hier ist es mal wieder sinnvoll, nicht immer als Admin unterwegs zu sein. Man muss die Einschränkungen des Constrained Modes genau kennen.

Einschränkungen des Constrained Modes

  • Alle cmdlets aus allen Windows Modulen funktionieren wie gewohnt – Ausnahmen können aber nicht ausgeschlossen sein (siehe weiter unten)
  • Alle Scriptelemente (Schleifen, Bedingungen, …) sind erlaubt
  • Das cmdlet Add-Type kann nur noch digital signierte Assemblies laden
  • new-Object kann nur noch „erlaubte“ Typen referenzieren
  • nur „erlaubte“ Typen können verwendet werden
  • Typkonvertierungen sind innerhalb der „erlaubten“ Typen möglich
  • cmdlets mit einer integrierten Typkonvertierung müssen „erlaubten“ Typen verwenden
  • Aus .net ist nur noch die ToString() Methode erlaubt
  • Es können alle möglichen Typwerte abgefragt werden. Geändert werden können nur noch Objekteigenschaften mit „erlaubten“ Typen

Welche Datentypen sind denn nun noch „erlaubt“?

AliasAttribute Hashtable PSTypeNameAttribute
AllowEmptyCollectionAttribute int Regex
AllowEmptyStringAttribute Int16 SByte
AllowNullAttribute long string
Array ManagementClass SupportsWildcardsAttribute
Bool ManagementObject SwitchParameter
byte ManagementObjectSearcher System.Globalization.CultureInfo
char NullString System.Net.IPAddress
CmdletBindingAttribute OutputTypeAttribute System.Net.Mail.MailAddress
DateTime ParameterAttribute System.Numerics.BigInteger
decimal PSCredential System.Security.SecureString
DirectoryEntry PSDefaultValueAttribute TimeSpan
DirectorySearcher PSListModifier UInt16
double PSObject UInt32
float PSPrimitiveDictionary UInt64
Guid PSReference

Vielleicht habt ihr bisher auch .net oder andere Datentypen als kleine Hilfsmittel verwendet. Das wird dann problematisch.

Achtung: PSLockDownPolicy-Bypass!

Der Constrained-Mode setzt den Einsatz der PowerShell-Version V5 voraus! Diese gibt es ab Windows 10 per Default an Bord des Betriebssystems. Wenn aber die PowerShell V2 auf dem gleichen System zuhause ist, kann ein Angreifer OHNE administrative Rechte einfach den Constrained Mode umgehen:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Natürlich ist die „alte“ Powershell nicht ganz so mächtig, wie man in meinem Beispiel sehen kann:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Aber es gibt genug Schadcode der für Windows 7 und damit für die PowerShell V2 geschrieben wurde. Daher würde ich empfehlen, dass die PowerShell V2 aus modernen Systemen entfernt wird. In Windows 10 wird sie zwar per Default erst dann nutzbar, wenn das DotNet-Framework 3.5 installiert ist, aber zur Sicherheit sollte die PS2 als optionales Windows-Feature deaktiviert werden:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Es genügt, die beiden Haken bei der Windows PowerShell zu entfernen. Danach kann ein Angreifer nicht mehr auf die alte Plattform wechseln:

PS-Security – PowerShell Constrained Language Mode (PSLockDown)

Fazit

Aus meiner Sicht hat Microsoft noch einiges an Arbeit vor sich, um das nützliche Werkzeug PowerShell vernünftig
abzusichern. Erste Ansätze sind erkennbar. Ich bleibe auf jeden Fall dran. Ihr auch?

Stay tuned!

PS: wer mag, kann meine ersten 5 Szenarien zur PS-Absicherung auch hier als PDF herunterladen. Die GPOs sind als Backup und html-Report natürlich auch mit dabei: WSHowto – PowerShell-Security