Skip to content

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:

  1. 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.
  2. 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".
  3. 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.
  4. 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".

Carsten Eilers

Trackbacks

Dipl.-Inform. Carsten Eilers am : Der Triple Handshake Angriff auf TLS im Web

Vorschau anzeigen
Wie angekündigt geht es in dieser Folge um den Einsatz des Triple Handshake Angriff auf TLS im Web. Wir erinnern uns... Nach dem dritten Schritt des Triple Handshake Angriffs geht der Client C davon aus, dass er mit dem Server des An

Dipl.-Inform. Carsten Eilers am : Neues rund um die Heartbleed-Schwachstelle

Vorschau anzeigen
Es gibt ein paar Neuigkeiten rund um die Heartbleed-Schwachstelle in OpenSSL: Weitere Angriffe entdeckt Es sind weitere Angriffe bekannt geworden, allerdings wurden alle erst nach Veröffentlichung der Patches und damit der Schwachstell

Dipl.-Inform. Carsten Eilers am : 2014 - Das Jahr, in dem die Schwachstellen Namen bekamen

Vorschau anzeigen
2014 wird als das Jahr in die Geschichte eingehen, in dem die Schwachstellen Namen bekamen. Vorher gab es bereits Namen für Schadsoftware, aber für Schwachstellen haben die sich erst dieses Jahr wirklich durchgesetzt. Die Schwachstelle von

Dipl.-Inform. Carsten Eilers am : Neues eBook: "Websecurity - Jahresrückblick 2014"

Vorschau anzeigen
&quot;Websecurity - Jahresrückblick 2014&quot; ist als eBook bei entwickler.press erschienen. Im ersten Kapitel dreht sich alles um die Angriffe auf und Schwachstellne in SSL und TLS, im zweiten Kapitel geht es um die weiteren prominenten Angri

Dipl.-Inform. Carsten Eilers am : Microsofts November-Patchday: 4 0-Day-Schwachstellen, aber keine Exploits

Vorschau anzeigen
Am November-Patchday hat Microsoft 4 0-Day-Schwachstellen behoben. Keine davon wird bisher ausgenutzt. Und keine davon ist auch nur im entferntesten kritisch. Noch besser sieht es bei Adobe aus: Im Flash Player wurden zwar 17 Schwachstelle be