Openswan: Denial-of-Service-Attacke mit zu langen IKE-Schlüsseln

Openswan ist eine vollständige IPsec-Implementierung für Linux, die aus dem FreeS/WAN Projekt hervorgegangen ist. Eine kürzlich entdeckte Sicherheitslücke darin hat zur Folge, dass ein entfernter Angreifer Openswan zum Absturz bringen kann.

IPsec (Internet Protocol Security) wird vorwiegend für den Aufbau virtueller privater Netzwerke (VPNs) verwendet und bietet hierzu Datenintegrität, Authentizität und Vertraulichkeit. Im Unterschied zu anderen Verfahren wie SSL, TLS, und SSH (die alle auf der Anwendungsschicht arbeiten) setzt IPsec schon auf der Vermittlungsschicht (Internet Layer) des TCP/IP-Protokollstacks (Schicht 3 des OSI-Modells) auf. Vorteilhaft an diesem Ansatz ist, dass Netzwerkanwendungen nicht speziell umgeschrieben werden müssen, um eine sichere Kommunikation zu gewährleisten.

Spezifikation

Der IPsec-Standard ist in RFC 2401 und 4301 beschrieben, wo die wesentlichen Protokoll-Spezifikationen von IPsec dargelegt werden. Diese unterteilen sich in zwei Funktionsgruppen: die Übertragungsprotokolle Authentication Header (AH, RFC 2402) und Encapsulated Security Payload (ESP, RFC 2406) sowie das Schlüsselmanagement, wozu das Key Management Protocol (ISAKMP, RFC 2408) und Internet Key Exchange (IKE, RFC 2409) gehören. Nachdem weitere Details ausgearbeitet wurden, findet sich die aktuelle IKEv2 Spezifikation in RFC 5996.

IKE definiert, wie Sicherheitsparameter vereinbart und gemeinsame Schlüssel (shared keys) ausgetauscht werden, und basiert auf ISAKMP. Wie der Name schon andeutet, bietet das Authentication Header Protokoll eine authentifizierte Kommunikation, aber keine Verschlüsselung der Daten. Es dient hauptsächlich dazu, Spoofing-Attacken zu verhindern und bietet zusätzlich Datenintegrität, das heißt, ein Angreifer kann Nutzdaten nicht manipulieren. Das AH-Protokoll bietet auch Schutz vor Replay-Attacken. Das Encapsulating Security Payload Protokoll bietet neben Dateintegrität und Authentifizierung auch Vertraulichkeit, das heißt, die übertragenen Daten werden von ESP verschlüsselt. Dadurch können sie dann von Dritten nicht mehr abgehört werden.

IPsec lässt sich in zwei verschiedenen Modi betreiben: Transport Mode oder Tunnel Mode. Der Transport Mode kommt beim Absichern von Punkt-zu-Punkt-Kommunikation zwischen zwei Hosts zum Einsatz, während der Tunnel Mode für das sichere Verbinden von Subnetzen mit Routern verwendet wird. In beiden Fällen macht IPsec von zwei lokalen Datenbanken Gebrauch: der Security Policy Database (SPD) und der Security Association Database (SAD). Die erste speichert Sicherheitsstrategien, wie beispielsweise eine bestimmte Punkt-zu-Punkt-Kommunikation abgesichert werden soll, während die zweite unter anderem Schlüssel speichert, also Sicherheitsassoziationen. Der Zugriff auf SPD-Einträge erfolgt anhand von Selektoren, die basierend auf dem IP-Paket (Ursprungs- und Zieladresse usw.) konstruiert werden. Die SAD-Datenbank wird nur dann abgefragt, wenn eine SPD-Abfrage ergibt, dass die gerade bearbeitete Verbindung abgesichert werden soll. Zur SAD-Abfrage enthält jeder Eintrag darin einen Sicherheitsparameter-Index (SPI), der in jedem IPsec geschützten Paket mitübertragen wird. Dadurch können die Hosts bei eingehenden Paketen den entsprechenden SAD-Eintrag anhand des SPI finden. Der Transportmodus schützt übergeordnete Protokollschichten. Da IPsec in der Netzwerkschicht implementiert ist, werden damit TCP- oder UDP-Header sowie Application-Header und Nutzdaten geschützt. Hierzu fügt IPsec hinter dem gewöhnlichen IP-Header einen extra IPsec-Header ein.

Programmierfehler

Die in Openswan entdeckte Sicherheitslücke erlaubt es einem entfernten Angreifer, Denial-of-Service-Attacken mit Hilfe präparierter IKE-Pakete durchzuführen. Ursache hierfür ist ein Programmierfehler in der Datei “programs/pluto/spdb_v1_struct.c”, wo ein Null-Zeiger-Dereferenzproblem auftritt. Das IKE-Protokoll verwendet zwei Phasen bei der Kommunikation, wobei Phase 1 darin besteht, einen sicheren authentifizierten Kommunikationskanal via ISAKMP aufzubauen. In Phase 2 wird dann die Security Association vereinbart. Der Programmierfehler tritt beim Verarbeiten der ISAKMP-Nachricht auf, wenn eine ungültige IKE-Schlüssellänge verwendet wird.

Dieses Problem wurde im Zuge von Commit 877454be8 am 19. September 2010 in Version 2.6.29 eingeführt. Dieser Commit sah folgende Änderungen für die Funktion “parse_isakmp_sa_body()” in der Datei “spdb_v1_struct.c” vor:

diff --git a/programs/pluto/spdb_v1_struct.c b/programs/pluto/spdb_v1_struct.c
index 8b180f2..56af219 100644
--- a/programs/pluto/spdb_v1_struct.c
+++ b/programs/pluto/spdb_v1_struct.c
@@ -880,7 +883,7 @@ parse_isakmp_sa_body( { case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV: #ifdef IKE_ALG
- if (ike_alg_enc_ok(val, 0, c->alg_info_ike, &ugh)) {
+ if (ike_alg_enc_ok(val, 0, c->alg_info_ike, &ugh, ugh_buf, sizeof(ugh_buf))) { /* if (ike_alg_enc_present(val)) { */ ta.encrypt = val; ta.encrypter = crypto_get_encrypter(val);
@@ -1139,7 +1142,7 @@ parse_isakmp_sa_body( * check if this keylen is compatible with * specified alg_info_ike */
- if (!ike_alg_enc_ok(ta.encrypt, val, c->alg_info_ike, &ugh)) {
+ if (!ike_alg_enc_ok(ta.encrypt, val, c->alg_info_ike, NULL, ugh_buf, sizeof(ugh_buf))) { ugh = "peer proposed key_len not valid for encrypt algo setup specified"; } ta.enckeylen=val;

Die Funktion “parse_isakmp_sa_body()” ist für das Verarbeiten von ISAKMP-Paketen zuständig. Der obige Code erledigt einige erste Kontrollen, wobei die Funktion “ike_alg_enc_ok()” verschiedene Eigenschaften des IKE-Pakets prüft. Der zweite Aufruf von “ike_alg_enc_ok()” prüft die Schlüssellänge (“keylen”). Wie der Git-Diff anzeigt, wurde die Funktion “ike_alg_enc_ok()” im Zuge des Commits um einige Argumente erweitert:

bool ike_alg_enc_ok(int ealg, unsigned key_len, struct alg_info_ike *alg_info_ike __attribute__((unused)), const char **errp, char *ugh_buf, size_t ugh_buf_len)
{ ... if (!ret && *errp) *errp = ugh_buf; return ret; ...
}

Dabei wird für den Schlüssellängen-Test das vierte Argument (der “errp”-Zeiger) auf NULL gestzt. Die gezeigt If-Anweisung in “ike_alg_enc_ok()” ist nun die Wurzel des Übels, weil dort dereferenziert auf “errp” zugegriffen wird, aber “errp” in diesem Fall auf NULL gesetzt ist. Das Dereferenzieren eines NULL-Zeigers ist selbstverständlich eine schlechte Idee, die im Allgemeinen zum Absturz des Programms führt. Ein entfernter Angreifer kann dies ausnutzen, um Denial-of-Service-Attacken auszuführen. Folgendes Beispielprogramm zeigt das Problem in vereinfachter Form:

#include <stdio.h>
#include <stdlib.h>
int main(void) { int a = 10; int *pa=&a; int **ppa =&pa; printf("a : %d\n", a); printf("*pa : %d\n", *pa); printf("**ppa : %d\n", **ppa); printf("&a : %p\n", &a); printf("pa : %p\n", pa); printf("*ppa : %p\n", *ppa); printf("&pa : %p\n", &pa); printf("ppa : %p\n", ppa); ppa=NULL; printf("ppa(NULL) : %p\n", ppa); /* no good idea...*/ printf("*ppa(NULL) : %p\n", *ppa); return EXIT_SUCCESS;
}

Hier wird am Ende “ppa” via “*” dereferenziert, obwohl “ppa” zuvor auf NULL gesetzt wurde. Das führt dann zu einem Segmentation Fault, wie die Ausgabe des Debuggers GDB zeigt:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400636 in main () at test.c:24
24 printf("*ppa(NULL) : %p\n", *ppa);

Die Openswan-Attacke ist für einen Angreifer nur möglich, falls er basierend auf seiner IP-Adresse eine Verbindung überhaupt aufbauen darf. Sollte Openswan so konfiguriert sein, dass dynamische Clients unterstützt werden, so kann ein Angreifer mit beliebiger Adresse die Attacke durchführen. Aber selbst wenn es IP-Beschränkungen gibt, so ist die Attacke mit Hilfe von Spoofing möglicherweise immer noch durchführbar. Im schlimmsten Fall kann eine solche Attacke ein ganzes Openswan-basiertes VPN in die Knie zwingen.

Der Patch für Schwachstelle besteht einfach darin, in der If-Abfrage nicht zu dereferenzieren:

if (!ret && errp) *errp = ugh_buf;
return ret;

Damit ist die Denial-of-Service-Attacke nicht mehr möglich, weil es natürlich legitim ist, “errp” abzufragen, was in diesem Fall auf NULL gesetzt ist.

Betroffen sind die Versionen 2.6.29 bis 2.6.35.

Nach oben