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.
- Sample script - Microsoft Teams firewall
PowerShell script
https://learn.microsoft.com/en-us/microsoftteams/client-firewall-script
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.
- Get-NetFirewallRule
https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallrule?view=windowsserver2022-ps - Enumerate Firewall Rules
https://learn.microsoft.com/en-us/samples/microsoft/windows-classic-samples/enumeratefirewallrules/
https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/security/windowsfirewall/enumeratefirewallrules/EnumerateFirewallRules.cpp - POSHTIP #31 – List Active Rules Of Your Windows Firewall
https://get-cmd.com/?p=3498 - Enumerating Firewall Rules
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa364724(v=vs.85)
Enumerate Windows Firewall rules using the Windows Firewall with Advanced Security APIs.
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
- PowerShell und UDP
- Get clients for Microsoft Teams
https://learn.microsoft.com/en-us/microsoftteams/get-clients?tabs=Windows - Sample script - Microsoft Teams firewall PowerShell script
https://learn.microsoft.com/en-us/microsoftteams/client-firewall-script - Is there any .NET API to get all the firewall rules
https://stackoverflow.com/questions/10342260/is-there-any-net-api-to-get-all-the-firewall-rules - How Windows Firewall knows whether it has prompted the user
to allow a program
https://fleexlab.blogspot.com/2016/12/how-windows-firewall-knows-whether-it.html