After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 653258 - Directory traversal bug in soup-uri.c using url-encoded periods
Directory traversal bug in soup-uri.c using url-encoded periods
Status: RESOLVED FIXED
Product: libsoup
Classification: Core
Component: HTTP Transport
2.34.x
Other Linux
: Normal normal
: ---
Assigned To: libsoup-maint@gnome.bugs
libsoup-maint@gnome.bugs
Depends on:
Blocks:
 
 
Reported: 2011-06-23 17:31 UTC by Mike Holloway
Modified: 2011-07-28 17:55 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
SoupServer: fix to not allow smuggling ".." into path (2.43 KB, patch)
2011-06-29 14:08 UTC, Dan Winship
none Details | Review

Description Mike Holloway 2011-06-23 17:31:59 UTC
While using gupnp which relies on libsoup, I saw a directory traversal attack was possible by url-encoding double-period segments (%2e) in the URI. 

In libsoup/soup-uri.c, adding this code prevents the vulnerability for me as a quick-fix:

                /* Remove url-encoded ".." */
                for (p = uri->path + 1; *p; ) {
                        if ( strncmp(p, "..", 2 == 0 ))
                        {
                                memmove (p, p + 2, strlen (p + 2) + 1);
                                p = uri->path + 1;
                        }
                        else if
                        (
                                strncmp (p, "%2e%2e", 6) == 0 ||
                                strncmp (p, "%2e%2E", 6) == 0 ||
                                strncmp (p, "%2E%2e", 6) == 0 ||
                                strncmp (p, "%2E%2E", 6) == 0 
                        )
                        {
                                memmove (p, p + 2, strlen (p + 2) + 1);
                                p += 6;
                        }
                        else
                                p++;
                }

                /* Remove "./" where "." is a complete segment. */


Example of the vulnerability, connecting to a GUPnP server:

> # telnet 198.18.9.240 39137
> Trying 198.18.9.240...
> Connected to 198.18.9.240.
> Escape character is '^]'.
> 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
>
> HTTP/1.0 200 OK
> Date: Fri, 15 Oct 2010 14:51:37 GMT
> Content-Type: text/plain
> Accept-Ranges: bytes
> Content-Length: 493
>
> root:x:0:0:root:/root:/bin/sh


-mike
Comment 1 Dan Winship 2011-06-24 14:02:05 UTC
I can't reproduce this with tests/simple-httpd in the libsoup sources, and I can't figure out how to make gupnp's tests/test-server work. Can you provided more detailed instructions on how to reproduce?
Comment 2 Mike Holloway 2011-06-24 16:27:37 UTC
Here is a very basic UPnP server (borrowed from gupnp/examples/light-server.c ), it might be easier to get working:

#include <libgupnp/gupnp.h>
#include <stdlib.h>
#include <gmodule.h>

int
main (int argc, char **argv)
{
  GMainLoop *main_loop;
  GError *error = NULL;
  GUPnPContext *context;
  GUPnPRootDevice *dev;

  g_thread_init (NULL);
  g_type_init ();

  /* Create the UPnP context */
  context = gupnp_context_new (NULL, argv[1], 0, &error);
  if (error) {
    g_printerr ("Error creating the GUPnP context: %s\n",
                error->message);
    g_error_free (error);

    return EXIT_FAILURE;
  }

  /* Create root device */
  dev = gupnp_root_device_new (context, "BinaryLight1.xml", "/tmp);
  gupnp_root_device_set_available (dev, TRUE);


  /* Run the main loop */
  main_loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (main_loop);

  /* Cleanup */
  g_main_loop_unref (main_loop);
  g_object_unref (dev);
  g_object_unref (context);

  return EXIT_SUCCESS;
}


Copy that into gupnp-0.x.y/examples/server.c and compile, then copy the provided BinaryLight1.xml into your /tmp directory before launching the server with ' ./server eth0 '. If you don't work with UPnP much, which listens for broadcast packets and then unicasts back a response including the high random port to connect to the server on via HTTP, you can find the listening port of the server by doing your OS equivalent of 'netstat -ant'. Then try the telnet and GET above to that port. You could also just use a web browser instead of telnet.

-mike
Comment 3 Dan Winship 2011-06-29 14:08:11 UTC
Created attachment 190933 [details] [review]
SoupServer: fix to not allow smuggling ".." into path

When SoupServer:raw-paths was set (the default), it was possible to
sneak ".." segments into the path passed to the SoupServerHandler,
which could then end up tricking some handlers into retrieving
arbitrary files from the filesystem. Fix that.
Comment 4 Dan Winship 2011-06-29 14:12:37 UTC
Does this patch look right? Does it leave any holes still?

Presumably this affects more than just test programs (Rygel?), and we're going to have to put out a security thingamabob about it...
Comment 5 Andreas Henriksson 2011-07-01 16:48:40 UTC
I can confirm that the testcase works against rygel...
Comment 6 Dan Winship 2011-07-11 21:51:03 UTC
This is now CVE-2011-2524, and Red Hat's security team is dealing with jumping through the requisite hoops. (And this bug is currently private to the people already cc:ed on it.)
Comment 7 Huzaifa Sidhpurwala (Red Hat Security Response) 2011-07-18 04:57:08 UTC
Is this patch final?

I would like to privately inform vendors about this issue and propose a Co-ordinated release date of 28-July-2011.

Does anyone copied on this email have any objections?
Comment 8 Dan Winship 2011-07-18 13:23:53 UTC
The patch is final unless anyone finds a way to exploit the bug still with that patch
Comment 9 Dan Winship 2011-07-28 17:55:20 UTC
fixed in master (libsoup-2.35.4) and gnome-3-0 branch (libsoup-2.34.3), and tarballs uploaded