Pylons                          Security Advisory

Topic:        Path traversal bug in default error controller
Module:       controllers/error.py
Announced:    2008-05-15
Credits:      Webwise Security
Affects:      All Pylons releases with Routes < 1.7.3
Corrected:    Routes 1.7.3 or greater
              Pylons 0.9.6.2

I. Background

The Pylons error.py controller is a default controller created in new Pylons projects. It handles serving media and the default error page for a Pylons
application.

II. Problem Description

The error.py controller uses paste.fileapp to serve the static resources to the browser. The default error.py controller uses os.path.join to combine the id from Routes with the media path. Routes prior to 1.8 double unquoted the PATH_INFO, resulting in FileApp returning files from the filesystem that
can be outside of the intended media path directory.

III. Impact

An attacker can craft URL's which utilize the double escaping to pass in a name to the error.py controller which contains a leading slash thus escaping the intended media path and serving files from any location on the filesystem
that the Pylons application has access to.

IV. Workaround

Any of the following will prevent the file traversal:

1) Upgrade Routes to Routes 1.7.3 (easy_install -U Routes)
This is a fix only for the multiple escaping which made it possible to
   exploit FileApp.
2) Remove the methods 'img' and 'style' from the ErrorController inside
controllers/error.py. These methods are only needed to serve the default error media, customizing the error page to render your own template doesn't
   require these 2 methods.
3) Patch the controllers/error.py controller to import urllib, and then
   urllib.quote_plus the id values before having them served by the
   fileapp.

V. Solution

For new Pylons projects, starting with Pylons 0.9.6.2, the project template
will include changes to ensure that the base media path is not escaped.

For existing Pylons projects perform one of the following:

1) Update the pylons/error.py to use the StaticURLParser, this requires the
   following changes:

   a) Replace the fileapp import at the top with:
       from paste.urlparser import StaticURLParser
b) Replace the img, style and _serve_file methods with the following ones:

       def img(self, id):
           """Serve Pylons' stock images"""
           return self._serve_file(os.path.join(media_path, 'img'), id)

       def style(self, id):
           """Serve Pylons' stock stylesheets"""
return self._serve_file(os.path.join(media_path, 'style'), id)

       def _serve_file(self, root, path):
"""Call Paste's FileApp (a WSGI application) to serve the file
           at the specified path
           """
           static = StaticURLParser(root)
           request.environ['PATH_INFO'] = '/%s' % path
           return static(request.environ, self.start_response)
2) Remove the 'img' and 'style' methods entirely. If the error.py 'document' method is loading a custom error handler, the additional methods to load
   Pylons media for the default error page is unnecessary.
3) Upgrade to Routes 1.7.3. This will prevent the double unquoting behavior, but is not as secure as option (1) as there is still no additional check that fileapp is being constrainted to the appropriate media directories.

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to