PowerShell und Windows Firewall

Auf dieser Seite geht es um ein aus meiner Sicht inkonsistentes Verhalten der Windows Firewall in Verbindung mit User Account Control (UAC) und welche Auswirkungen ein Deny des Anwenders auf das Gesamtsystem mit PowerShell haben kann.

Sicherheitshinweis

Bei der Entwicklung meiner Skripte wie End2End-UDP3478, wurde die Anwender immer wieder mit einer Firewall-Meldung konfrontiert, die ich gerne vermieden hätte.

Die Meldung wurde durch eine Zeile in der PowerShell getriggert.

Um ein UDP-Paket zu senden, muss ich natürlich einen UDP-Client bereitstellen, der theoretisch auch ohne ein ausgehendes Paket schon ein Paket empfangen kann. Für die Windows Firewall ist es daher zurecht der Versuch einen "Listen-Port" zu öffnen.

Interessant dabei ist, dass die Ausführung des Skripts dadurch nicht angehalten wurde und auch die Funktion selbst in diesem Fall nicht beeinträchtigt war.

Ablehnung reicht

Im Regelfall ist ein Anwender natürlich kein lokaler Administrator aber nur auf dem "Zugriff zulassen"-Button ist das "UAC-Schild" sichtbar. Als normaler Benutzer kann ich einfach "abbrechen". Das Fenster verschwindet aber das Skript funktioniert dennoch problemlos weiter. Mein Code kann ohne Beeinträchtigung weiter UDP-Pakete senden und sogar empfangen. Die Funktion benötigt im Grund keine explizite Konfiguration der Desktop-Firewall. Allerdings sehe ich das Ergebnis meiner Ablehnung durchaus in der Firewall-Konfiguration, die ich auch als nicht privilegierter Benutzer einsehen kann. Ich war zu der Zeit in einem Domainnetzwerk und folgende beiden Regeln wurden dennoch addiert:

Ich habe aber keinen Weg gefunden, wie ich als DomainUser schon vorab solche "Blockieren"-Regeln addieren könnte, um z.B. die Rückfrage beim Anwender zu unterbinden. Vielleicht ist es aber auch besser, dass ich das nicht machen kann. Ich könnte dann eventuell auch absichtlich per "Deny" vom Administrator gewünschte Regeln außer Kraft setzen.

Hier die Details zu den Regeln per PowerShell:

PS C:\group\Technik\Skripte\end2end\end2end-udp3478> Get-NetFirewallRule -DisplayName pwsh

Name                          : TCP Query User{BEC8B238-C941-486D-BA0E-F896DDA766C1}C:\program files\powershell\7\pwsh.exe
DisplayName                   : pwsh
Description                   : pwsh
DisplayGroup                  :
Group                         :
Enabled                       : True
Profile                       : Domain, Public
Platform                      : {}
Direction                     : Inbound
Action                        : Block
EdgeTraversalPolicy           : Block
LooseSourceMapping            : False
LocalOnlyMapping              : False
Owner                         :
PrimaryStatus                 : OK
Status                        : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536)
EnforcementStatus             : NotApplicable
PolicyStoreSource             : PersistentStore
PolicyStoreSourceType         : Local
RemoteDynamicKeywordAddresses : {}

Name                          : UDP Query User{8DDB6537-9150-4B26-95FC-B9F8523355E6}C:\program files\powershell\7\pwsh.exe
DisplayName                   : pwsh
Description                   : pwsh
DisplayGroup                  :
Group                         :
Enabled                       : True
Profile                       : Domain, Public
Platform                      : {}
Direction                     : Inbound
Action                        : Block
EdgeTraversalPolicy           : Block
LooseSourceMapping            : False
LocalOnlyMapping              : False
Owner                         :
PrimaryStatus                 : OK
Status                        : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536)
EnforcementStatus             : NotApplicable
PolicyStoreSource             : PersistentStore
PolicyStoreSourceType         : Local
RemoteDynamicKeywordAddresses : {}

Obwohl ich nur eine ausgehende UDP-Verbindung aktiviert hatte, addiert Windows bei einer Ablehnung ein "Block" auf alle eingehenden UDP und TCP-Verbindungen. Da ich ein PowerShell-Skript geschrieben habe, wird nicht das Skript selbst sondern der PowerShell-Prozess als Quelle addiert.

Fragen zum Abbruch

Das wirft nun folgende Fragen bei mir auf:

  • Ein Prozess blockt alle weitere Entwicklung?
    Wenn ein einziges PowerShell-Skript in Verbindung mit eine "Abbrechen" die Shell komplett von eingehenden Verbindungen abblockt, dann kommt auch bei anderen Skripten keine Rückfrage mehr.
  • Warum ANY und nicht nur dieser eine UDP-Port?
    Ich binde per UDP genau einen Port und hätte erwartet, dass ein "Abbrechen" genau diese Erlaubnis nicht erteilt. Ich habe nirgendwo eine TCP-Verbindung auch nur versucht. Gleich alle TCP/UDP-Verbindungen des Prozess zu blocken verhindert später Rückfragen, wenn ein anderes Skript einen anderen Port öffnen möchte.
  • Berechtigungen
    Mir ist auch noch nicht klar, von welchem Prozess und mit welchen Berechtigungen der Eintrag addiert wurde. Die Regeln kann ich über REGEDIT finden aber "Besitzer" sind die Administratoren.

Natürlich kann ich all diese Probleme umgehen, wenn ich z.B. über eine Setup-Logik die passende Firewall-Regel vorab anlege. Das sollte bei klassisch installierten Programmen ja auch der Regelfall sein und moderne Apps in Form von im Browser laufenden JavaScript-Code fallen auch nicht weiter auf, solange sie keine Ports öffnen.

Dennoch sollten Sie als Administrator dieses Verhalten kennen und wenn ein z.B. in PowerShell geschriebener Service nicht erreichbar ist. Vielleicht gibt es von früheren Aktionen schon diese DENY-Regeln.

UAC-Abhängigkeit

Interessanterweise ist die Einstellung von UAC (Benutzerkontensteuerung) für die Einrichtung einer automatischen Firewall-Regel nicht relevant.

UAC Einstellung PowerShell Egebnis

Immer benachrichtigen

User (kann zum Admin werden)

Firewallprompt

Immer benachrichtigen

Admin

Firewallprompt

Nur Benachrichtigen, wenn Apps Änderungen vornehmen (Standard)

User (kann zum Admin werden)

Firewallprompt

Nur Benachrichtigen, wenn Apps Änderungen vornehmen (Standard)

Admin

Firewallprompt

Nur Benachrichtigen, wenn Apps Änderungen vornehmen (Desktop nicht abblenden)

User (kann zum Admin werden)

Firewallprompt

Nur Benachrichtigen, wenn Apps Änderungen vornehmen (Desktop nicht abblenden)

Admin

Firewallprompt

Nie

User (kann zum Admin werden)

Firewallprompt

Nie

Admin

Firewallprompt

Es war egal, wie UAC eingestellt war und ob ich die Shell als Admin oder User gestartet habe. Ich bekam IMMER eine Firewall-Dialogbox zur Bestätigung und "Zulassen" war immer mit einem Schutzschild ausgezeichnet. Allerdings hat hier dann wieder die UAC-Einstellung gegriffen. Wenn hier ein "Nie" aktiv war, dann konnte ich als Benutzer, der über UAC auch Admin werden konnte, direkt die Erlaubnis oder wetere UAC-Rückfrage erteilen.

Zum Testen habe ich einfach UDP-Ports wie folgt geöffnet und danach die PowerShell immer wieder geschlossen.

$udpClient4 = new-Object system.Net.Sockets.Udpclient(40004)

Allow-Verhalten

Wenn ich hingegen lokale Administratoren-Rechte habe oder sich geben können, dann ändert sich das Verhalten. Wobei ich das Verhalten auch ungewöhnlich finde, wenn zum einen werden zwei "Allow"-Regeln addiert, die sowohl UDP aber auch TCP in dem Netzwerk erlauben, welches ich ausgewählt habe.

Zudem werden aber ebenfalls "Deny"-Regeln für das öffentliche Netz addiert. Natürlich habe ich die Checkbox auf dem Dialog hierfür auch nicht aktiviert aber es gibt wohl keinen "grau"-Status, der einfach keine Regel addiert. Interessant auch, dass "Privat"-Netzwerk nicht eingetragen werden.

Wie machen es andere?

Ich habe natürlich geschaut, ob ich in meinem Code etwas ändern kann, um diese Meldung nicht zu triggern. Ich benötige für meine Funktion ja keine eingehende Verbindung, da end2end-udp3478 nur Daten sendet und die Antwort auf ausgehende Pakete wieder einsammelt. Ich konnte aber keine Lösung finden. Stattdessen habe ich gerade bei Microsoft Teams den Hinweis gefunden, dass es wohl "Design" ist und wenn Microsoft es nicht umgehen kann, dann gibt es wohl keine Lösung

When users initiate a call using the Teams client for the first time, they might notice a warning with the Windows firewall settings that asks for users to allow communication. Users might be instructed to ignore this message because the call will work, even when the warning is dismissed.
Quelle: Get clients for Microsoft Teams - https://learn.microsoft.com/en-us/microsoftteams/get-clients?tabs=Windows

Die "Lösung" von Microsoft für das Produkt "Microsoft Teams, welches ja als Benutzer installiert wird, besteht in einem PowerShell-Skript zum Eintragen einer Regel pro Benutzer mit administrativen Berechtigungen.

Das ist natürlich eine sehr schwache Lösung, da die Regel auf den Pfad zur "Teams.exe" zielt und nur für die bislang jemals angemeldeten Benutzer eingetragen wird. Neue Anwender bekommen weiter den Dialog, wenn UAC entsprechend eingerichtet ist.

Eine pauschale Regel auf Ports wäre aber auch keine Lösung.

Warne deine Anwender

Wenn die Software nicht gleich als Administrator "installiert" wird, dann ist es ratsam die Existenz einer passenden Regel zu prüfen und den Benutzer auf den UAC-Dialog hinzuweisen. Auch eine Erwähnung in der Dokumentation und Anleitung ist keine schlechte Idee.

Ein Entwickler kann seine Software also dazu bringen, die aktuellen Firewall-Regeln auszulesen und zu prüfen, ob das eigene Programm entsprechend berücksichtigt ist.

Wer keine API nutzen will, kann sich auch an einem direkten Lesen der Registrierung versuchen

HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRule

Zwischenstand

Ich meine, die Windows Firewall sollte genauer prüfen, ob es sich wirklich um eine eingehende Verbindung handelt, die hier ein Client öffnen möchte. Da das bei UDP nicht so einfach ist, könnte eine eine Definition im Manifest oder ein erweiterter Funktionsaufruf anzeigen, ob eine Software nur ausgehende Verbindungen nutzen möchte. Dann könnte die Windows Firewall entsprechende abgestimmt auf ihre eigene Konfiguration entscheiden, ob der Benutzer für die ausgehenden Verbindungen eine Rückfrage erhalten muss.

So bleibt es aber dabei, dass ich für die Nutzung von Socket, UDP-Port oder TCP-Ports nicht verhindern kann, dass die Firewall den Anwender fragt und dieser dann doch einfach ein "Cancel/Abbrechen" drücken darf. Wenn der Anwender dann mit "Abbrechen" den Dialog beendet, dann habe ich im schlimmsten Fall eine DENY-Regel für "PowerShell.exe" oder "pwsh.exe", die der Benutzer selbst gar nicht mehr entfernen kann.

Auf der anderen Seite ist es vielleicht gerade gut, dass ein durch den Anwender gestartetes Skript oder Programm nach einer Rückfrage erst einmal auf Dauer ein "Deny" hat. Schließlich gibt es nur ganz wenig Szenarien, bei denen ein Anwendersystem eingehende Verbindungen annehmen sollte.

Weitere Links