Neuer Angriff auf TLS beim Einsatz von Client-Zertifikaten
Es wurde ein neuer Angriff auf das TLS-Protokoll entdeckt, der den Einsatz von Client-Zertifikaten betrifft: Verbindet sich ein TLS-Client mit einem bösartigen Server und präsentiert dem sein Zertifikat, kann der Server sich gegenüber einen anderen Server, der dieses Zertifikat akzeptiert, als der betreffende Benutzer ausgeben.
Drei Handshakes sind gefährlich
Die Schwachstelle wurde von Karthikeyan Bhargavan, Antoine Delignat-Lavaud und Alfredo Pironti vom Forscherteam "Prosecco" des INRIA Paris-Rocquencourt, Cédric Fournet von Microsoft Research, Cambridge, und Pierre-Yves Strub vom IMDEA Software Institute in einem Paper beschrieben: "Triple Handshakes and Cookie Cutters: Breaking and Fixing Authentication over TLS" (PDF). Zusätzlich gibt es eine Website zur Schwachstelle: "Triple Handshakes Considered Harmful: Breaking and Fixing Authentication over TLS". Außer den schon genannten Forschern waren auch noch Markulf Kohlweiss und Santiago Zanella-Béguelin von Microsoft Research, Cambridge, an der Arbeit beteiligt.
Vier Schwachpunkte im TLS-Protokoll
Der neue Angriff verwendet Standard-Features des Protokolls, die in unerwarteter Weise kombiniert werden. Konkret geht es um die folgenden vier Features:
- Beim RSA-Handshake sendet ein Client C das Pre-Master Secret (PMS) an
einen Server A und verschlüsselt es dabei mit dem öffentlichen
Schlüssel von A. Ist A bösartig, kann er sich gegenüber
einen anderen Server S als Client ausgeben und in einer neuen Verbindung
das gleiche PMS an S senden. Die zwei Verbindungen können weiter
synchronisiert werden, da A für beide die gleichen Zufallswerte
für Client und Server und den gleichen Session Identifier (SID)
verwenden kann.
Danach gibt es zwei Verbindungen mit identischen Identifier, Master Secret (MS) und Verbindungsschlüsseln, aber zwischen verschiedenen Kommunikationspartnern. Insbesondere das Server-Zertifikat ist unterschiedlich. Aus Schlüsselaustausch-Sicht handelt es sich dabei um eine "Unknown Key-Share Attack" (UKS), die an sich noch keine schwerwiegende Schwachstelle ist. Erst die Kombination mit den weiteren Problemen macht sie gefährlich. - Beim DHE-Handshake wählt Server A die Diffie-Hellman
Gruppen-Parameter. Ist A bösartig, kann er eine Gruppe wählen,
die nicht Prim ist, so dass das sich ergebende PMS unter seiner Kontrolle
ist.
Wie im Fall von RSA kann der bösartige Server als Man-in-the-Middle zwischen einem Client C und einem Server S agieren, indem er zwei Sessions mit identischen SID, MS und Verbindungsschlüssel aufbaut. Auch dies entspricht einer "Unknown Key-Share Attack". - Beim Wiederaufbau einer Session auf einer neuen Verbindung wird ein
abgekürzter Handshake verwendet, der nur prüft, dass Client und
Server die gleichen MS, Chipersuiten und SID (oder vom Server ausgegebenes
Session-Ticket) verwenden. Insbesondere erfolgt keine erneute
Authentifizierung von Client und Server.
Wenn ein bösartiger Server A also eine "Unknown Key-Share Attack" durchführt um zwei Sessions (eine mit C, die andere mit S) mit gleicher MS, Chiphersuite und SID aufzubauen, kann er den verkürzten Handshake von einer Verbindung zur anderen weiterleiten. Der verkürzte Handshake garantiert nicht, dass die ursprünglichen Handshakes die gleichen waren. Die "Renegotiation Indication Extension" (RFC 5746) bindet die Renegotiation-Handshakes nur an die TLS-Verbindung, über die sie abgewickelt werden, greift aber nicht beim Wiederaufbau der Session mit einer neuen Verbindung. - Während der Neuverhandlung (Renegotiation) der Verbindung können sich laut TLS-Protokoll (und dessen meisten Implementierungen) sowohl Client- als auch Server-Zertifikat ändern. Es gibt aber keine Regeln, wie die Anwendungen auf solche Änderungen reagieren sollen. Einige Implementierungen verknüpfen die Verbindung mit dem ersten Zertifikat, andere mit dem letzten, aber beides ist nicht unbedingt die beste Wahl.
Der Triple Handshake Angriff
Der Angriff richtet sich gegen den Client C und den Server S, die den RSA Schlüsselaustausch verwenden und sowohl Wiederaufnahme (Resumption) als auch Neuverhandlung (Renegotiation) der Verbindung erlauben. Der Server akzeptiert Verbindungen von beliebigen, auch nicht authentifizierten Clients, führt dann aber irgendwann, zum Beispiel beim Zugriff auf eine Ressource mit Zugriffsbeschränkungen, eine Neuverhandlung durch, bei der der Client über ein Client-Zertifikat authentifiziert wird. Der Angriff erfolgt in drei Schritten:
Schritt 1:
Client C baut eine Verbindung zum bösartigen Server A auf, ohne von dessen
Bösartigkeit zu wissen. Danach baut A als Client eine Verbindung zu S auf
und verwendet dabei den von C erhaltenen Client-Zufallswert (client random,
cr). Den vom S erhaltenen Server-Zufallswert (server random, sr) und SID
sendet A weiter an C. Zusätzlich zwingt A C und S, den RSA
Schlüsselaustausch zu verwenden, indem er nur die dazu passenden
Ciphersuiten in den Handshakes anbietet.
A entschlüsselt dann den von C verschlüsselt an ihn gesendeten PMS und
verschlüsselt ihn neu für S. Danach schließt er beide Handshakes
vollständig ab, um auf beiden Verbindungen eine neue Session zu erhalten.
Beide Sessions verwenden die gleichen Schlüssel und Session-Parameter (sid,
ms, cr, sr), haben aber unterschiedliche Server-Zertifikate und
Abschluss-Nachrichten (verify_data).
In der folgenden Abbildung sind die Originalwerte blau hervorgehoben, die
vom bösartigen Server A geänderten Werte rot.
Benutzer Angreifer Ziel Client C Server A Server S ¦ ¦ ¦ ¦--> ClientHello(cr, [RSA, DH], ...) -------->¦ ¦ ¦ ¦--> ClientHello(cr, [RSA], ...) ---------------->¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerHello(sr, sid, RSA, ENC_ALG) <---------¦ ¦ ¦ ¦ ¦ ¦<-- ServerCertificate(cert_S, pk_S) <------------¦ ¦<-- ServerCertificate(cert_A, pk_A) <--------¦ ¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerHelloDone <----------------------------¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦--> ClientKeyExchange(rsa(pms, pk_A)) ------>¦ ¦ ¦ ¦--> ClientKeyExchange(rsa(pms, pk_S)) ---------->¦ ¦ ¦ ¦ ¦--> ClientCCS -------------------------------------------------------------------------------->¦ ¦ ¦ ¦ ¦--> ClientFinished(verifydata(log_1, ms)) -->¦ ¦ ¦ ¦--> ClientFinished(verifydata(log'_1, ms)) ----->¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerCCS <----------------------------------¦ ¦ ¦ ¦ ¦ ¦<-- ServerFinished(verifydata(log_2, ms)) <------¦ ¦<-- ServerFinished(verifydata(log'_2, ms)) <-¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ neue Session: kennt: neue Session: sid, ms, anon->cert_A sid, ms, cr, sr sid, ms, anon->cert_S cr, sr, RSA, ENC_ALG ¦ cr, sr, RSA, ENC_ALG ¦ ¦ ¦ ¦ ¦ ¦ ¦--> Anwendungs-Daten ------------------------------------------------------------------------->¦ ¦<------------------------------------------------ Anwendungs-Daten <---------------------------¦ ¦ ¦ ¦
Varianten des Angriffs erlauben auch Angriffe auf Clients und Server, die DHE verwenden oder von Anfang an eine Client-Authentifizierung erzwingen.
Schritt 2:
C verbindet sich erneut mit A und bittet darum, die vorherige Session
wieder aufzunehmen (Resumption). A wiederum verbindet sich erneut mit S
und nimmt dort ebenfalls die vorherige Session wieder auf. Da alle
relevanten Parameter der beiden Sessions identisch sind, kann A die von ihm
empfangenen Nachrichten des verkürzten Handshakes einfach an C bzw. S
weiterleiten. Nach Abschluss des verkürzten Handshakes verwenden beide
Sessions erneut die gleichen Schlüssel, haben nun aber auch die gleiche
Abschluss-Nachricht (verify_data). A kennt die neuen Verbindungsschlüssel,
so dass er weiterhin Daten auf beiden Verbindungen (zu C und S) senden kann.
Benutzer Angreifer Ziel Client C Server A Server S ¦ ¦ ¦ vorhandene Session: kennt: vorhandene Session: sid, ms, anon->cert_A sid, ms, cr, sr sid, ms, anon->cert_S cr, sr, RSA, ENC_ALG ¦ cr, sr, RSA, ENC_ALG ¦ ¦ ¦ ¦--> ClientHello(cr', sid) -------------------------------------------------------------------->¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerHello(sr', sid) <----------------------¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerCCS <----------------------------------¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerFinished(cvd=verifydata(log_1, ms)) <--¦ ¦ ¦ ¦ ¦--> ClientCCS -------------------------------------------------------------------------------->¦ ¦ ¦ ¦ ¦--> ClientFinished(svd=verifydata(log_2, ms)) ------------------------------------------------>¦ ¦ ¦ ¦ neue Verbindung: kennt: neue Verbindung: sid, ms, cr', sr', cvd, svd sid, ms, cr', sr' sid, ms, cr', sr', cvd, svd ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦--> Anwendungs-Daten ------------------------------------------------------------------------->¦ ¦<------------------------------------------------ Anwendungs-Daten <---------------------------¦ ¦ ¦ ¦
Zu diesem Zeitpunkt glaubt C weiterhin, dass er eine Verbindung mit A hat, und S glaubt, dass er eine Verbindung mit einem anonymen Client hat - bisher hat sich niemand für irgend jemanden ausgegeben. Da aber für Client und Server verify_data für beide Verbindungen identisch sind hat die Renegotiation Indication Extension für die nächsten Handshakes auf diesen Verbindungen die gleichen Werte. Außerdem ist das "TLS-unique" Channel Binding (RFC 5929), durch das die TLS-Authentifizierung an einen Kanal gebunden wird, auf beiden Verbindungen identisch, was die eigentlichen Intention in ihr Gegenteil verkehrt: Statt der Anwendung zu erlauben, sich auf die TLS-Authentifizierung für einen bestimmten Kanal zu verlassen, wird das Binding nun dafür genutzt, der Anwendung eine falsche Authentifizierung unter zu schieben.
Schritt 3:
A provoziert S dazu, auf seiner Verbindung mit A eine Neuverhandlung
(Renegotiation) der Verbindung mit Client-Authentifizierung zu verlangen.
Dazu kann A zum Beispiel auf eine zugriffsgeschützte Ressource
zugreifen. A leitet den Renegotiation-Request an C weiter, und C
authentifiziert sich mit seinem Client-Zertifikat bei A. Nun wird auf
beiden Verbindungen ein vollständiger Renegotiation-Handshake mit
Client-Authentifizierung durchgeführt. A leitet dabei einfach alle von
C erhaltenen Nachrichten an S weiter und umgekehrt. Der Handshake endet
erfolgreich, da die erwarteten Werte der Renegotiation Indication Extension
auf beiden Verbindungen identisch sind.
Nach Abschluss der Renegotiation kennt A Sitzungsschlüssel und Master-Secret nicht mehr, diese sind nur noch C und S bekannt. Also kann A auf beiden Verbindungen keine Nachrichten mehr lesen oder senden. Vorher gesendete Nachrichten können aber so vorbereitet sein, dass sie nach der Renegotiation ausgetauschten Nachrichten entsprechen. Bei einem Web-basierten Angriff kann A außerdem auf Grund der Same-Origin Policy weiterhin in der Lage sein, Daten auf diesen Verbindungen zu lesen oder zu schreiben.
Benutzer Angreifer Ziel Client C Server A Server S ¦ ¦ ¦ vorhandene Session: kennt: vorhandene Session: sid, ms, anon->cert_A sid, ms, cr, sr sid, ms, anon->cert_S cr, sr, RSA, ENC_ALG ¦ cr, sr, RSA, ENC_ALG ¦ ¦ ¦ vorhandene Verbindung: kennt: vorhandene Verbindung: sid, ms, cr', sr', cvd, svd sid, ms, cr', sr' sid, ms, cr', sr', cvd, svd ¦ ¦ ¦ ¦<-- Anwendungs-Daten_1 -------------------------- Anwendungs-Daten_2 ------------------------->¦ ¦ ¦ ¦ ¦--> ClientHello(cr", [KEX_ALG'], [ENC_ALG'], cvd) -------------------------------------------->¦ ¦ ¦ ¦ ¦<------------------------------------ ServerHello(sr", sid', KEX_ALG', ENC_ALG', cvd, svd) <---¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerCertificate(cert_S, pk_S) <------------¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerKeyExchange(sign(kex_s, sk_s)) <-------¦ ¦ ¦ ¦ ¦<------------------------------------------------ CertificateRequest <-------------------------¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerHelloDone <----------------------------¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦--> ClientCertificate(cert_C, pk_C)) --------------------------------------------------------->¦ ¦ ¦ ¦ ¦--> ClientKeyExchange(kex_C) ----------------------------------------------------------------->¦ ¦ ¦ ¦ ¦--> CertificateVerify(sign(log_1, sk_C), cert_C) --------------------------------------------->¦ ¦ ¦ ¦ ¦--> ClientCCS -------------------------------------------------------------------------------->¦ ¦ ¦ ¦ ¦--> ClientFinished(verifydata(log_2, ms') ---------------------------------------------------->¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerCCS <----------------------------------¦ ¦ ¦ ¦ ¦<------------------------------------------------ ServerFinished(verifydata(log_3, ms')) <-----¦ ¦ ¦ ¦ ¦ ¦ ¦ neue Session: kennt: neue Session: sid', ms', cert_C->cert_S cert_C sid, ms, cert_C->cert_S cr", sr", KEX_ALG', ENC_ALG' ¦ cr", sr", KEX_ALG', ENC_ALG' ¦ ¦ ¦ ¦--> Anwendungs-Daten_3------------------------------------------------------------------------>¦ ¦ ¦ ¦ ¦<------------------------------------------------ Anwendungs-Daten_4 <-------------------------¦ ¦ ¦ ¦ Erhalten von A: Erhalten von C: Anwendungs-Daten_1 Anwendungs-Daten_2 + + Anwendungs-Daten_4 Anwendungs-Daten_3
Alle drei Handshakes zusammen sehen Sie hier.
Wer spielt mit bei "Zertifikat wechsle dich"?
Während des Renegotiation-Handshakes empfängt C das Zertifikat von S, obwohl er denkt, mit A verbunden zu sein. Man sollte erwarten, dass C diesen Zertifikatswechsel nicht akzeptiert, aber viele TLS-Clients einschließlich populärer Webbrowser erlauben den Austausch des Server-Zertifikats, ohne den Benutzer zu warnen.
Dafür gibt es mehrere mögliche Gründe. Zum Beispiel kann ein Server so eine andere Ciphersuite aushandeln oder ein während einer lange laufenden TLS-Session abgelaufenes Zertifikat ersetzen. Auch ist es dadurch möglich, ein anfänglich verwendetes allgemeines (schwaches) Zertifikat durch ein spezifischeres (stärkeres) Zertifikat auszutauschen. Besonders sicher ist das aber nicht, wie der vorgestellte Angriff zeigt.
Gegenmaßnahmen
Um die Angriffe vollständig zu verhindern, muss das Protokoll geändert werden. Es gibt aber einige mögliche Schutzmaßnahmen, die auch ohne Protokolländerung umgesetzt werden können. Zum Beispiel kann die Änderung des Server-Zertifikats währen der Renegotiation verboten werden (zum Beispiel implementiert in Chromium), alle empfangenen Zertifikate können gründlich geprüft werden (insbesondere muss das Zertifikat zum aktuellen Server passen, was eigentlich eine Selbstverständlichkeit ist), das Master-Secret kann an den vollständigen Handshake gebunden werden, und der vereinfachte Handshake zur Session-Resumption kann an den ursprünglichen Handshake gebunden werden.
Für einige betroffene Programme und Libraries gibt es bereits Updates oder Patches, für andere werden sie noch getestet oder auch nur diskutiert.
Wie geht es weiter? Wie webbasierte Angriffe ablaufen können ist das Thema der nächsten Folge, die in 14 Tagen erscheint. In der nächsten Woche ist die CeBIT, und daher gibt es am kommenden Donnerstag meinen traditionellen "Bericht von der CeBIT".
Trackbacks
Dipl.-Inform. Carsten Eilers am : Der Triple Handshake Angriff auf TLS im Web
Vorschau anzeigen
Dipl.-Inform. Carsten Eilers am : Neues rund um die Heartbleed-Schwachstelle
Vorschau anzeigen
Dipl.-Inform. Carsten Eilers am : Drucksache: Entwickler Magazin 1.2015 - SSL/TLS im Jahr 2014: Herzbluten, ein bissiger Poodle und Co.
Vorschau anzeigen
Dipl.-Inform. Carsten Eilers am : 2014 - Das Jahr, in dem die Schwachstellen Namen bekamen
Vorschau anzeigen
Dipl.-Inform. Carsten Eilers am : Neues eBook: "Websecurity - Jahresrückblick 2014"
Vorschau anzeigen
Dipl.-Inform. Carsten Eilers am : Microsofts November-Patchday: 4 0-Day-Schwachstellen, aber keine Exploits
Vorschau anzeigen