Fix-RDPCertificate

Das folgende Skript korrigiert das für RDP zugewiesene Zertifikat, da seit Windows 2012 es dazu keine MMC oder GUI mehr gibt.

Problemstellung

Verbindungen per RDP sollten natürlich verschlüsselt sein, damit nicht nur die Nutzdaten sondern auch die Anmeldung selbst gesichert ist. Viel wichtiger ist aber die Gewissheit, auch auf dem richtigen Server gelandet zu sein. Denn für einen Angreifer ist es durchaus möglich, eine RDP-Verbindung auf einen DNS-Namen oder eine IP-Adresse umzuleiten. DNS-Spoofing ist zwar etwas aufwändiger aber ARP-Spoofing ist in einem LAN relativ einfach möglich. Wenn Sie dann als Administrator per MSTSC.EXE sich verbinden, dann wollen Sie ja sicher sein, dass die Gegenstelle kein Angreifer ist.

Genau dafür sind Zertifikate da und folgende Meldung sollten Sie beim Zugriff per RDP nicht als "normal" wegklicken, sondern die Ursache beseitigen.

Diese Meldung bedeutet nämlich, dass MSTSC.EXE eine TLS-Verbindung versucht aber das vom Server gelieferte Zertifikat nicht übereinstimmt. Da gibt es wieder die bekannten Prüfungen, die alle erfolgreich verlaufen müssen.

  • Name des Servers in der Verbindung stimmt mit dem Namen im Zertifikat überein
  • Das Zertifikat ist noch gültig und nicht abgelaufen
  • Ausstellende CA vertrauenswürdig
  • Das Zertifikat ist nicht zurückgezogen worden (CRL-Check)

Das schreit ja geradezu nach einem Automatismus zur Überwachung und Aktualisierung.

Computer Zertifikat installieren

Das weiter unten aufgelistete Skript legt selbst kein Zertifikat an und fordert auch keines an. Dies ist Aufgabe eines Administrators und eines passenden PKI-Konzepts. Sie müssen aber nicht für jeden Computer nun ein öffentliches Zertifikat kaufen. Oft geht das auch nicht, wenn Sie z.B.: intern eine DNS-Domäne nutzen, die ihnen extern nicht gehört oder die es gar nicht als offizielle Toplevel-Domain gibt, z.B. ".intern".

Ich empfehle mittlerweile allen Kunden mit einer entsprechenden Größe und Anforderungen an die Sicherheit den Betrieb einer internen privaten PKI, der alle eigenen Computer vertrauen. Wenn man diese PKI z.B. nur für die Ausstellung von Zertifikaten für Computer, Webseiten, Smartcards und Code-Signing verwendet, dann muss man auch keine privaten Schlüssel sichern, sondern zieht das verlorene Zertifikat einfach zurück und stellt ein neues Zertifikat aus. Die Zertifizierungsstelle muss natürlich trotzdem einen Mindeststandard einhalten, insbesondere wenn Sie Zertifikate für Codesigning oder Smartcard-Anmeldung ausstellen.

Über eine entsprechende Gruppenrichtlinie können und sollten sie dann auch dafür sorgen, dass jeder Computer in ihrer Domäne ein "Computer-Zertifikat" bekommt, indem der DNS-Name und auch der kurze NetBIOS-Name enthalten ist.

Manuell zuweisen

Seit Windows 2012 gibt es keine MMC, mit der man die Eigenschaften des RDP-Listeners bearbeiten kann. Aus meiner Sicht ist das quasi unverständlich denn im Gegenzug hat Microsoft auch keine Logik hinterlegt, mit der Windows sich dann ein geeignetes Zertifikat selbst sucht. Exchange macht das zumindest etwas besser, da ein Administrator mehrere Zertifikate im Store ablegen und aktivieren kann und Exchange sich selbst ein "passendes" Zertifikat sucht.

Bei RDP ist das leider anders. Microsoft hat selbst in einem KB-Artikel das Vorgehen dokumentiert.

Es gibt also nur zwei Optionen:

  • WMI
    Sie können über einen WMI-Aufruf kann ich den Hash-Wert des Zertifikats hinterlegen
  • Registrierung
    Der WMI-Aufruf speichert die Einstellung und letztlich ist es ein Wert in der Registrierung, den ich auch manuell setzen kann

Per PowerShell geht dies recht einfach

# Zertifikat per PowerShell und WMI senden 
$path = (Get-WmiObject -class “Win32_TSGeneralSetting” -Namespace root\cimv2\terminalservices -Filter “TerminalName=’RDP-tcp'”).__path
Set-WmiInstance -Path $path -argument @{SSLCertificateSHA1Hash=”ThumbprintWithoutSpaces”}

Registrierungsschlüssel können Sie durch einen Import mit einer REG-Datei oder auch per PowerShell setzen

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp]
"SSLCertificateSHA1Hash"=hex:00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
  00,00,00,00

Allerdings müssen sie dazu natürlich erst wieder einen Hashwert eines Zertifikats ermittelt haben. Ein statischer Eintrag in einer Textdatei oder einem Skript ist nicht wirklich brauchbar.

Automatisch zuweisen

Ich mir habe daher überlegt, wie ich diese Zuordnung automatisieren kann. Meine Lösung basiert wieder auf einem PowerShell-Skript, welches das bestehende Zertifikat prüft und ggfls. ersetzt.

Das Skript baut also darauf auf, das es bereits ein Zertifikat mit privatem Schlüssel im lokalen Zertifikatsspeicher des Computers gibt. Es fordert also selbst keine Zertifikate an.

Es sucht dann alle Zertifikat und nutzt folgende Logik das passende Zertifikat zu finden. Zuerst entfernt es Zertifikate, die nicht funktionieren weil Sie...

  • ... DNS-Name des Computers nicht im Subject oder SAN-Eintrag haben
    Ich gehe davon aus, dass der Zugriff über den Namen und nicht über die IP-Adresse erfolgt und Aliasnamen dann hoffentlich auch im SAN-Eintrag alle enthalten sind.
  • ... Keinen privaten Schlüssel haben
    Denn ohne passenden privaten Schlüssel ist das Zertifikat nicht brauchbar. Sie sollten sich natürlich mal fragen, welchen Sinn so ein Zertifikat auf dem System hat.
  • ... Gültigkeit nicht gegeben ist
    Zertifikate laufen irgendwann ja ab und kaum jemand bereinigt
  • ... Die EnhancedKeyUsageList nicht "Computer Identifizierung" (OID "1.3.6.1.5.5.7.3.1")) oder "Remote Desktop Authentication" ("1.3.6.1.4.1.311.54.1.2") enthält.
  • ... SelfSigned sind. Sinnvoll ist nur PKI Zertifikate

Die dann übrig gebliebenen Zertifikate werden nach der Gültigkeit sortiert. Die Aufgabe könnte mit mit einer Arraylist (die es bei Powershell 2 aber noch nicht gab) und pfiffigerem Code vermutlich schneller lösen. Ich habe aber "lesbaren" Weg gewählt, den man vielleicht leichter versteht.

Automatic Bindung

Mit Windows 2022 scheint es ein Automapping zu geben. Dazu muss ich eine eigene interne PKI haben, mit der ich dann z.B. per Gruppenrichtlinie automatische das "richtige" Zertifikat auf die Clients ausrolle. Ich muss dazu ein neues Template anlegen, welches z.B. alle "Domain Computer" per "READ+ENROLL" nutzen dürften und einen bestimmten ObjectIdentifier hat:

Name: SSL Secured RD
Object Identifier: 1.3.6.1.4.1.311.54.1.2

Der Wert landet dann in der "EnhancedKeyUsageList" im Zertifikat. Dann brauche ich eine Gruppenrichtlinie oder andere Automatisierung, welches das Zertifikat auf jedem relevanten Server anfordert. Microsoft reät von einem "Autoenrollment" ab.

Es gibt schon mehrere Beschreibungen, so dass ich dies hier nicht noch mal wiederhole.

Skripte

Das folgende Skripte können Sie einfach wieder auf einem Server kopieren und also Admin (Wegen WMI) aufrufen. Es sucht sich die Zertifikate und zeit an, welches es zuweisen würde und welches aktuell zugewiesen ist. Wenn Sie den Switch "updatecertificatebinding" addieren, dann erfolgt auch die Zuweisung.

fix-rdpcertificate.ps1.txt

Ich bin nicht sicher, ob der Code in allen Umgebungen arbeitet. Bitte prüfen Sie dies.

Module Remote Management

Von Microsoft gibt es seit Windows 2022 in Verbindung mit der "Remotedesktopdienste-Bereitstellung" auch ein eigenes Module "RemoteDesktop", mit dem das Zertifikat-Handling verbessert wurde.

Andere Lösungen

In einem Forum habe ich folgenden Code gefunden, welcher das Powershell-Module "RemoteDesktopServices" nutzt.

Import-Module RemoteDesktopServices
$Date = (Get-Date).AddMinutes(-150)
$Cert = Get-ChildItem CERT:LocalMachine/My | ? {$_.NotBefore -gt $Date}
if ($Cert) {
   Write-Host "Installing new certificate.."
   cd RDS:\RDSConfiguration\Connections\RDP-Tcp\SecuritySettings
   Set-Item .\SSLCertificateSHA1Hash -Value $Cert.Thumbprint 
}
   else {
   Write-Host "No recent certificates found."
}

Bei mir hat es aber nicht funktioniert.

Weitere Links