In diesem kleinen WSHowTo zeige ich euch, wie ich meine Infrastruktur von der Altlast NTLM befreit habe. Natürlich gehört das Wissen um die Theorie dazu. Daher beginnen wir mit einigen Erklärungen. Im 2. Teil zeige ich euch meine eigene Umstellung. Im 3. Teil seht ihr verschiedene meiner Services, bei denen ich Anpassungen vornehmen musste.
Inhaltsverzeichnis
Zweck
Anmeldeinformationen sollen vertrauliche Daten und Dienste schützen. In unseren Infrastrukturen finden wir an allen relevanten Punkten Authentifizierungslösungen. Die meisten verwenden dabei Benutzernamen und Kennworte. Wer die Kombination aus beiden kennt, kann auf die Services und Daten zugreifen.
Wir bemühen uns, dass diese Anmeldeinformationen unser Geheimnis bleiben: wir schreiben keine Kennworte frei zugänglich auf, nutzen Password-Safes und jeder Benutzeraccount hat ein anderes Kennwort (oder? )
Dabei ist das nur ein Teil der Lösung. Denn insgesamt sind 3 Punkte in einer Authentifizierung zu schützen:
- Die Identität – also der Benutzer, der seine Kennworte geheimhält.
- Der Authentifizierungsdienst, der die Anmeldeinformationen prüfen soll – auch dieser muss die Anmeldeinformationen kennen
- Und zuletzt: der Übertragungsweg der Anmeldeinformationen von der Identität zum Authentifizierungsdienst.
Der Übertragungsweg ist generell als unsicher zu betrachten – bitte auch in internen Netzwerken! Ich habe schon einige Beispiele in meinem Hacking-Blog vorgestellt, mit denen es gelingt, die Anmeldeinformationen während der Authentifizierung abzugreifen. Sehr gerne nutze ich dazu den Responder. In Kombination mit MultiRelay.py kann sehr einfach die Anmeldung eines Administrators umgeleitet werden, um als Angreifer ein Zielsystem zu übernehmen. Aber auch ein Responder alleine kann bereits Anmeldeinfos aufzeichnen. Diese könnten offline geknackt werden.
Jedesmal, wenn das Passwort im Klartext oder gehashed übertragen wird, kann ein Angriff erfolgreich sein. Über viele Jahre war NTLM eine Möglichkeit, die Anmeldung vorzunehmen. Bei der aktuellen Version NTLMv2 wird nicht das Passwort bzw. der Hash des Passwortes übertragen. Stattdessen wird eine Challenge (eine Zufallszahl) mit dem Hash vom Client berechnet und zum Server übertragen. Der Server kann die Challenge ebenfalls berechnen (er muss dazu Zugriff auf den Hash des Passwortes vom Benutzer haben). Sind die Ergebnisse der Challenge identisch, dann kann der Server dem Client einen Zugriff gestatten:
Aber ein Angreifer kann aus der Zufallszahl und dem Ergebnis der Challenge den NTLM-Hash bzw. das dazugehörige Passwort OFFLINE berechnen.
Seit vielen Jahren empfiehlt Microsoft nun schon, NTLM im Active Directory zu verbieten und statt dessen vollständig auf Kerberos zu setzen. Dieses Protokoll ist wesentlich sicherer.
Natürlich müssen dafür alle Abhängigkeiten von NTLM geklärt werden, damit es keine Anmeldeprobleme oder Zugriffsprobleme im Netzwerk gibt. Dies beginnt bei der Nutzung kompatibler Clients und Services und umfasst auch die korrekte Konfiguration aller Dienste. Das Standardverfahren zur Deaktivierung von NTLM sieht daher vor, dass über einen Referenzzeitraum ein Audit der Nutzung von NTLM auf allen DomainControllern mitläuft. Erst wenn alle Services angepasst sind, wird die Verwendung von NTLM abgeschaltet.
NTLM im Active Directory?
Aber warum werden die DomainController überwacht? Ganz einfach: der Zielserver kann nicht von jedem Benutzer den PasswortHash kennen. Er muss einen DomainController fragen. Das sieht dann so aus:
Im Wireshark kann man die Pakete sehr schön erkennen. Ich habe das Szenario einmal mit 4 Servern nachgestellt:
- Auf S-SVR1 (172.16.1.11) ist die Benutzerin Tessa.Test angemeldet.
- Sie greift auf den Server S-SVR2 (172.16.1.12) mit dem Windows Explorer zu. Dabei verwendet Sie den UNC-Pfad \\172.16.1.12 – Kerberos kann also nicht verwendet werden, denn dafür sind DNS-Namen erforderlich.
- S-SVR2 antwortet im Paket 18 mit der NTLM-Challenge – der Zufallszahl.
- S-SVR1 berechnet aus dem NTLM-Hash von Tessa (dieser liegt nach der Anmeldung im LSA vor) die Challenge-Response und sendet diese an S-SVR2 im Paket 19
- S-SVR2 baut nun eine Verbindung zum S-DC1 (172.16.1.1) auf. Im Paket 26 überträgt er mit dem Longterm-Service-Key aus seiner Kerberos-Anmeldung die Challenge und den Challenge-Response vom S-SVR1 an den Domain Controller.
- Der DC kennt alle Benutzer und hat deren NTLM-Hashes gespeichert. Er entschlüsselt die ChallengeWerte aus Paket 26, berechnet selbst die Response und antwortet S-SVR2 in Paket 27, dass die Response korrekt ist. Somit weiß S-SVR2 nun, dass Tessa.Test auch die echte Tessa ist.
- Im Paket 28 bestätigt S-SVR2 nun die erfolgreiche Anmeldung an S-SVR1 – Tessa kann nun mit dem Fileserver arbeiten
Was ist nun daran problematisch? Jedes Paket wie #19 stellt ein Risiko dar, da es abgefangen und geknackt werden kann!
NTLM-Audit
Aktivieren wir nun das Audit auf allen DomainControllern, dann schreiben diese in ein spezielles Eventlog alle eingehenden Anfragen von DomainMembern nieder. Diese können dann zentral ausgewertet werden.
Die Aktivierung wird über eine GPO vorgenommen:
Diese wirkt auf alle DomainController. Ergebnisse des Audits findet man in diesem Eventlog:
Das Auslesen der Eventlogs über ALLE DomainController und Analysieren kann man mit der PowerShell etwas vereinfachen:
Invoke-Command -ComputerName (Get-ADDomain).ReplicaDirectoryServers -ScriptBlock { Get-WinEvent -Path C:\Windows\System32\Winevt\Logs\Microsoft-Windows-NTLM%4Operational.evtx | Select-Object -Property @{ n='DC' ; e={ $env:COMPUTERNAME } }, @{ n='Datetime' ; e={ (Get-Date -Date $_.TimeCreated -Format u) -replace 'z' } }, @{ n='Client' ; e={ (($_.Message -split "`n" | select-string 'Workstation') -split ':')[1].trim() } }, @{ n='Server' ; e={ (($_.Message -split "`n" | select-string 'Secure Channel name') -split ':')[1].trim() } }, @{ n='Domain' ; e={ (($_.Message -split "`n" | select-string 'Domain name') -split ':')[1].trim() } }, @{ n='User' ; e={ (($_.Message -split "`n" | select-string 'User name') -split ':')[1].trim() } } } | Format-Table -Property DC,Datetime,Client,Server,Domain,User
Die Ergebnisse werden tabellarisch dargestellt:
NTLM-Deaktivierung
Wurden alle Konfigurationen an Kerberos angepasst, dann kann mit einer weiteren GPO NTLM auf den DomainControllern deaktiviert werden. Clients werden zwar weiterhin ihre Challenge-Responses bei Bedarf verwenden und Server werden diese wie bisher an den DomainController weiterleiten. Aber der DC wird sich weigern, die Response für den Server zu berechnen. Der Server kann also nicht mehr bestimmen, ob der Client für den Zugriff autorisiert ist – und daher lehnt er den Verbindungsaufbau ab!
Nur dieses Nichtzustandekommen der Verbindung wird der IT-Abteilung gemeldet. Und diese kann sich dann dem Problem annehmen und Konfigurationen zur Verbesserung der Sicherheit anpassen. Das klingt nach Arbeit? Jup – Sicherheit hat eben ihren Preis!
Für Systeme, die nicht ohne NTLM-Auth auskommen kann in der GPO eine Ausnahme definiert werden. Mit diesen sollte man aber sparsam umgehen – sonst bringt es nichts. Die Logfiles können zur Bestimmung der Ausnahmen dienen.
Die Deaktivierung (mit einer Ausnahme für den Server S-SVR3) könnte nun so aussehen:
Wenn nun NACH der Deaktivierung von NTLM ein Client eine NTLM-Session zu einem Server anfragt und dieser Server die Anmeldeinformationen bei einem DomainController prüfen möchte, dann wird dieser keine positive Auskunft mehr erteilen. Die Verbindung wird fehlschlagen:
Im WireShark kann man den Prozess wieder schön beobachten:
- Der Client mit der IP 172.16.1.11 fragt im Paket 14 eine SMB-Session beim Server 172.16.1.12 an.
- Im Paket 15 sendet der Server eine NTLM-Challenge zum Client.
- Der Client nutzt den NTLM-Hash des Benutzers, um daraus und aus der Challenge die Challenge-Response zu berechnen. Diese sendet er im Paket 16 an den Server.
Man sieht hier ganz deutlich, dass die NTLM-Deaktivierung NICHT von den Clients und den Servern erzwungen wird! Die NTLM-Responses werden nach wie vor über das unsichere Netzwerk geleitet!!!
- Der Server fragt nun beim Domaincontroller (IP 172.16.1.1) nach, indem er die Challenge-Response mit Kerberos verschlüsselt im Paket 30 an den DC sendet.
- Der DC weiß, dass er keine NTLM-Authentifizierungen mehr prüfen soll. Nach einer kurzen Prüfung, ob der Server in der Ausnahmeliste steht, verweigert er in Paket 31 die Authentifizierung.
- Der Server informiert den Client im Paket 32, dass diese Anmeldeform nicht unterstützt wird.
Am Client sieht meine Testuserin ein AccessDenied:
Nutzt meine Testuserin dagenen den Namen des Servers im Windows Explorer (und hängt der Client den DomainName an, damit ein FQDN gebildet werden kann), dann klappt die Verbindung:
Im Wireshark sieht man deutlich, dass nun der Client (172.16.1.11) zum DomainController (172.16.1.1) ein TGS-Request sendet, in dem er für den Service CIFS (SMB) auf dem Server S-SVR2 (172.16.1.12) ein SessionTickek erbittet. Da der Name passt und auch alle anderen Voraussetzungen erfüllt sind, erhält der Client das Ticket. Dieses sendet er dann an den Server. Und dieser bestätigt die Verbindung:
Es ist also nicht wirklich schwer, das Anmeldeverhalten zu analysieren.
Im folgenden Text beschreibe ich die Umstellung in meiner eigenen Infrastruktur.
IST-Situation
In meinem Netzwerk setze ich auf Windows Server 2012R2 und Windows Server 2016. Alle Clients laufen mindestens mit Windows 10 Enterprise V1709. Es existieren einige Nicht-Microsoft-Systeme. Die meisten Services kommen direkt von Microsoft und sind auf dem aktuellen Stand der Technik. Es sollte keine Probleme bei der Umstellung geben.
Dennoch habe ich das Audit aktiviert. Das ist generell auch bei einer Deaktivierung von NTLM empfehlenswert, denn vielleicht kommen morgen neue Services mit NTLM ums Eck.
Wie zu erwarten kamen einige Treffer zusammen (ein kleiner Auszug):
Betroffene Services sind
- mein PRTG-Monitoring, dass sich vom WS-IPM aus auf verschiedene Services zur Überwachung aufschaltet – darunter auch meine NAS WS-NAS1
- verschiedene Zugriffe auf meine RDS-Plattform
- Ein Zugriff meines AdminAccounts vom DPM-Server auf einen der Fileserver
Jeder Treffer im Logfile muss analysiert werden Dabei kann auch eine Zusammenfassung helfen:
cls; Invoke-Command -ComputerName (Get-ADDomain).ReplicaDirectoryServers -ScriptBlock { Get-WinEvent -Path C:\Windows\System32\Winevt\Logs\Microsoft-Windows-NTLM%4Operational.evtx -ErrorAction SilentlyContinue | Select-Object -Property @{ n='DC' ; e={ $env:COMPUTERNAME } }, @{ n='Datetime' ; e={ (Get-Date -Date $_.TimeCreated -Format u) -replace 'z' } }, @{ n='Client' ; e={ (($_.Message -split "`n" | select-string 'Arbeitsstationsname') -replace '\\' -split ':')[1].trim() } }, @{ n='Server' ; e={ (($_.Message -split "`n" | select-string 'Name des sicheren Kanals') -split ':')[1].trim() } }, @{ n='Domain' ; e={ (($_.Message -split "`n" | select-string 'Domänenname') -split ':')[1].trim() } }, @{ n='User' ; e={ (($_.Message -split "`n" | select-string 'Benutzername') -split ':')[1].trim() } } } | Group-Object -Property Client,Server,User | Sort-Object -Property Count | Select-Object -Property count,@{n='Connection';e={ $Val = $_.name -split ', ' $Val[0] + " -> " + $Val[1] + " (" + $Val[2] + ")" }} | Format-Table -Property count,Connection
Das Ergebnis sieht so aus:
Nach diversen Tests konnte ich 4 Services ausmachen, die ich genauer kontrollieren wollte:
- meine Exchange Server (WS-MX1 und WS-MX2)
- meine Microsoft VPN-Lösung (WS-RA1 und WS-RA2)
- meine RDS-Farm (WS-RDS1, WS-RDS2)
- meinen PRTG-MonitoringService (WS-IPM)
Alle anderen sollten wich bei der Aushandlung auf Kerberos verständigen können.
Umstellung auf NoNTLM
Die Umstellung war durch eine scharfe GPO und deren Anwendung auf 3 DomainController recht schnell erledigt. Nun ging es an das TroubleShooting.
Und dabei habe ich immer das Logfile beobachtet!
Exchange Server (2016)
Ich verwende Outlook im internen Netzwerk und auch außerhalb. Zudem nutze ich bei Bedarf OWA und selbstverständlich ActiveSync auf SmartPhones.
Mein Outlook hatte Intern sofort eine Verbindung. Ebenso klappt der Verbindungsaufbau von extern:
Auch ActiveSync scheint keine Probleme zu haben. Ebenso funktioniert OWA über FBA.
VPN-Einwahl mit Windows RemoteAccess
Leider sieht das bei meiner VPN-Lösung nicht ganz so fein aus. Aktuell habe ich einen RemoteAccessCluster aus 2 Servern bereitgestellt. Beide bieten nach außen VPN mit SSTP über eine Zertifikatabsicherung auf TCP Port 443 an. Für die Authentifizierung verwendete ich bisher Benutzername und Kennwort von den ActiveDirectory-Benutzern. Die RemoteAccessServer leiteten diese Infos an ihren NPS (NetworkPolicyServer) weiter. Und dieser prüfte gegen die DomainController – mit NTLM… ☹
OK, die Absicherung war eh nicht mehr zeitgemäß. Ich wollte generell auf Smartcard-Anmeldung umstellen. Dank vSmartcard mit Windows 10 und meinem TPM ging das recht einfach. Nun musste ich nur noch die Netzwerkrichtlinien auf meinen NPS anpassen:
Und schon komm ich wieder per VPN in mein Netzwerk! So haben sich das wohl auch die Entwickler bei Microsoft vorgestellt:
- NTLM wird deaktiviert
- unsichere Zugänge werden entdeckt
- unsichere Zugänge werden gegen sichere Zugänge ersetzt bzw. die Konfigurationen werden angepasst
RemoteDesktop in einer RDS-Farm
Bei meinem RemoteDesktopService (RDS) gab es eine ähnliche Überraschung. Im internen Netzwerk funktionierte alles wie gewohnt – da Kerberos zur Verfügung steht.
Komme ich aber von außen auf meine RDS-Infrastruktur, dann muss ich das RDS-Gateway verwenden. Dieses tunnelt das RDP-Protokoll in einem https-Datenstrom. Damit mich das Gateway erkennt muss ich mich an ihm anmelden. Und das Gateway fragt im Hintergrund beim DomainController via NTLM an… ☹
Der RD-Gateway verwendet ebenfalls einen lokalen NPS. In diesem gibt es eine Standard-Zugriffsrichtlinie. Diese verwendet aktuell ein Passwort (und damit NTLM). Alternativ kann ich auch hier auf eine Smartcard-Anmeldung umstellen. Da ich meine RDS-Anwendungen aber auch außerhalb meines eigenen Rechners verwenden möchte kann ich nicht auf Smartcard umstellen. Hier werde ich noch einmal gesondert nach einer Lösung suchen. Bis dahin verwende ich diese eine Maschine in der Ausnahmeliste – und lasse somit NTLM für einen Server zu.
PKI-Sperrlistenveröffentlichung
Mein Monitoring meldete mir, dass die Sperrlisten meiner Windows PKI nicht mehr aktualisiert werden.
Ein Blick ins Eventlog des Servers zeigte das Problem:
Was war passiert?
- In meiner CDP-Erweiterung hatte ich eine http-Seite für den Download der Sperrliste hinterlegt:
- Diese Website läuft auf einem anderen Server. Den Namen der Seite hatte ich mit http://crl.ws.its/… angegeben.
- Der Webserver ist mein WS-RA1.
- Über DNS hatte ich einen HostA-Record für crl.ws.its erstellt und auf die IP-Adresse von WS-RA1 zeigen lassen.
- Mein PKI-Server muss die Sperrlisten über SMB auf WS-RA1 übertragen.
- Dafür hatte ich die Freigabe crl-distribution$ auf WS-RA1 erstellt.
- Und meiner PKI hatte ich den Pfad \\crl.ws.its\crl-distribution$… für die Sperrlistenveröffentlichung hinterlegt.
Bisher konnte das System den Namen crl.ws.its in die IP-Adresse des Servers WS-RA1 übersetzen und dann den Schreibzugriff auf die Freigabe anfordern. Da der Name aber nicht mit dem echten Namen übereinstimmte konnte meine PKI kein Kerberos verwenden (crl.ws.its hatte ich nur im DNS verwendet!). Also verwendete die PKI einfach NTLM. Und mit der Deaktivierung von NTLM war damit Schluss!
Hier war es recht einfach, den Anmeldeprozess auf Kerberos umzustellen, da es sich „nur“ um eine Fehlkonfiguration handelte. Ich nahm den falschen Eintrag aus den Sperrlistenverteilungspunkten raus und ersetzte ihn durch den FQDN des Zielservers:
Fazit: die Umstellung ist machbar, benötigt aber fundierte Kenntnisse und eine sehr gute Vorbereitung!
Wie immer könnt ihr hier das ZipFile mit allen Unterlagen und den Scripten herunterladen: WSHowTo – Deaktivierung von NTLM
Stay tuned! 🙂