Libsoup: Double-Dot-Attacke macht Server-Dateien lesbar

Seitdem das HTTP-Protokoll aus dem CERN hervorging, ist die Zahl der HTTP-Server- und Client-Applikationen dramatisch angestiegen. Die Bibliothek Libsoup bietet ein einfaches auf GObject und Glib beruhendes Framework zum Entwickeln solcher Software. Eine vor wenigen Tagen korrigierte Sicherheitslücke erlaubt es einem entfernten Angreifer, Dateien auf dem Server zu lesen.

Libsoup ist dank GObject objektorientiert und lässt sich einfach verwenden. Ein Client benutzt beispielsweise ein “SoupSession”-Objekt, um die Sessions zu verwalten und kann HTTP-Nachrichten als “SoupMessage”-Objekte erzeugen:

SoupMessage *msg;
msg = soup_message_new ("GET", "http://example.com/");

Das Beispiel generiert eine HTTP-GET-Anfrage an example.com. Genauso einfach lassen sich auch HTTP-Server mit Libsoup realisieren. Diese basieren auf dem Objekt “SoupServer” und benötigen Callback-Funktionen für verschiedene Pfade: Nach dem Erzeugen des “SoupServer-Objekts” liefert der Server zunächst nur “404 Not Found” zurück. Erst wenn der Programmierer eine Callback-Funktion für bestimmte Pfade mit “soup_server_add_handler()” hinzufügt, kann der Server sinnvoll arbeiten. Diese Callback-Funktionen folgen immer folgendem Gerüst:

static voidserver_callback(SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data)
{ ...
}

Dabei enthält “path” den Pfad der GET-Anfrage. Das detaillierte Verhalten des HTTP Servers lässt sich durch verschiedene Eigenschaften des “SoupServer”-Objekts beeinflussen. Beispielsweise steuert die Eigenschaft “SoupServer:raw-paths”, ob URIs automatisch dekodiert werden (falls FALSE). Diese Variable wird standardmäßig auf FALSE gesetzt, da URI-Encoding sehr häufig zum Einsatz kommt. Damit ist es nämlich möglich, beliebige Byte-Folgen in der URI zu kodieren ohne mit reservierten Zeichen zu kollidieren.

Der Soup-Server ist in der Datei “soup-server.c” der Bibliothek implementiert. Sie enthält unter anderem die Funktion “got_headers()”, die zum Verarbeiten von Client-Anfragen aufgerufen wird. Fall “raw-paths” auf FALSE gesetzt ist, kommt folgender Code zum Aufruf:

if (!priv->raw_paths) { char *decoded_path; uri = soup_message_get_uri (req); decoded_path = soup_uri_decode (uri->path); soup_uri_set_path (uri, decoded_path); g_free (decoded_path);
}

Der URI-kodierte Pfad wird hier mit “soup_uri_decode()” dekodiert und dann zurück in die Struktur SoupURI *uri kopiert. Hier hat sich eine leicht auszunutzende Schwachstelle eingeschlichen. Denn die “soup_uri_decode()”-Funktion dekodiert “%2e%2e%2f” korrekterweise zu “../”. Sendet also ein Client folgende GET-Anfrage an den Server:

GET /%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd HTTP/1.0

so wird dieser Pfad zu “/../../../../../../../../../etc/passwd” dekodiert. Sind genügend “../” Zeichen vorhanden, um aus dem Server-Verzeichnis auf die Root-Ebene auszubrechen, so verlangt diese GET-Anfrage die “/etc/passwd”-Datei des Server. Wie “ls -l” zeigt ist die Passwortdatei typischerweise für jeden Benutzer lesbar, also auch von dem Libsoup-Serverprozess:

mark@tux:~$ ls -l /etc/passwd
-rw-r--r-- 1 root root 1895 2011-03-11 03:52 /etc/passwd

Der Server liefert dem Client als Antwort auf dessen GET-Anfrage also die passwd-Datei zurück. Diese Attacke ist natürlich nicht auf die “passwd”-Datei beschränkt: Jede für den Server-Prozess lesbare Datei des Systems kann so heruntergeladen werden. Die Schwachstelle lässt sich einfach mit Telnet ausnutzen, indem der Angreifer eine Verbindung zum Server aufbaut und dann die GET-Anfrage sendet.

Die Lücke wurde Mitte Juli 2011 Git-Repository gestopft und Ende des Monats in Version 2.35.4 korrigiert. Das Patch besteht darin, den Pfad nach dem Dekodieren auf die Zeichenfolge “../” zu prüfen:

if (strstr (decoded_path, "/../") || g_str_has_suffix (decoded_path, "/..")) { /* Introducing new ".." segments is not allowed */ g_free (decoded_path); soup_message_set_status (req, SOUP_STATUS_BAD_REQUEST); return;
}

Falls die kritische Zeichenfolge “../” in dem dekodierten Pfad entdeckt wird, sendet der Server nun einfach eine “SOUP_STATUS_BAD_REQUEST”-Antwort an den Client zurück.

Entdeckungsgeschichte: Die Libsoup-Schwachstelle wurde ursprünglich in einer GUPnP-Applikation von Mike Holloway Ende Juni entdeckt. Das GUPnP-Framework dient zum Verwalten von UPnP-Geräten und verwendet die Libsoup-Bibliothek.

Nach oben