classification
Title: information leakage with SimpleHTTPServer
Type: security Stage: resolved
Components: Library (Lib) Versions: Python 2.7, Python 2.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: orsenthil Nosy List: Arfrever, Huzaifa.Sidhpurwala, asdfasdfasdfasdfasdfasdfasdf, barry, benjamin.peterson, brett.cannon, dmalcolm, eric.araujo, georg.brandl, gps, gregory.p.smith, grubert, jcon, ori.livneh, orsenthil, rhettinger
Priority: critical Keywords: patch

Created on 2011-02-11 18:46 by brett.cannon, last changed 2011-07-21 00:13 by ori.livneh. This issue is now closed.

Files
File name Uploaded Description Edit
translate_path.patch ori.livneh, 2011-06-06 02:11 Proposed patch to http.server review
translate_path_rev2.patch ori.livneh, 2011-06-13 00:58 Update of proposed patch review
Messages (16)
msg128420 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2011-02-11 18:46
As reported to the PSRT:

Python's SimpleHTTPServer class is a simple HTTP server, documented as
serving up the content of the pwd and below readonly via GET and HEAD
commands:

 $ python -m SimpleHTTPServer
 Serving HTTP on 0.0.0.0 port 8000 ...

However, by inserting "../" path fragments within the path section of
the URL, it's possible to traverse other directories within the
filesystem.

For example:

 lynx localhost:8000/../../../../..

shows 5 directories above in the directory structure.

I was also able to browse /proc and /sys on this example using:

 lynx localhost:8000/../../../../../../../../proc
 lynx localhost:8000/../../../../../../../../sys

(by browsing to find the correct number of ".." entries to locate the
root directory); arguable this could be leaking much more information
about the host than the administrator might be expecting (e.g. other
programs being executed on the host, command-line arguments of those
programs etc)

This has been fixed in CGIHTTPServer; see
 http://bugs.python.org/issue2254
and:
 http://svn.python.org/view?view=rev&revision=71303

Guido recommended to not make this secret since no one should be using SimpleHTTPServer in production. He also said this should get fixed.
msg128423 - (view) Author: Dave Malcolm (dmalcolm) (Python committer) Date: 2011-02-11 19:36
CVE-2011-0705
msg128439 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2011-02-12 07:31
This would be nice to fix in 3.2; however, since SimpleHTTPServer is not meant to be used in production, and it's not a regression, I will not hold up the release schedule for it.  I'd need to see a patch for deciding.
msg128480 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2011-02-13 05:42
Agreed, fixing this is going to be too complex for 3.2.0, it'll be done for 3.2.1.

Reading over the http.server Simple and CGI HTTPRequestHandler code I see there many problems with the way this code does things today.

General:
 * I'm not sure urllib.parse.unquote() is called on the path in the correct place all the time.  Studying of some RFCs will be required to confirm that.  Specifically the CGI handler unquotes the path before fixing it up.  The Simple handler never unquotes the path.

Simple (and subclasses such as CGI):
 * The mentioned directory traversal vulnerability.

CGI:
 * The _url_collapse_path_split called by is_cgi lets os.sep's through unchecked so a request for /foo/bar\..\..\..\..\..\../ for example should still find its way out on windows.  issue2254 wasn't 100% fixed.
 * _url_collapse_path_split should really ignore the query string and anchor; though the way it is used it likely just wastes time processing them and discarding the result.
 * It uses fork() + execve() on posix systems. It should always use subprocess instead in order to be thread safe.

The first thing I'll be doing is coming up with test cases demonstrating each of these issues.
msg128483 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2011-02-13 09:46
Lowering priority.
msg129260 - (view) Author: david (asdfasdfasdfasdfasdfasdfasdf) Date: 2011-02-24 12:21
This may be stupid but...

shouldn't the example be:

lynx http://localhost:8000/../../../../../etc/passwd

... which does _not_ work.
msg136054 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2011-05-15 22:57
unassigning, i don't have time for this one right now.  doubtful anyone is going to jump in for 3.2.1 given rc1 is being prepared right now. :)

General recommendation: don't use SimpleHTTPServer in production.
msg137726 - (view) Author: Ori Livneh (ori.livneh) * Date: 2011-06-06 02:11
I've attached my proposal for a fix. It's my first, so apologies if I've made a mistake somewhere. Senthil Kumaran, to whom the bug is currently assigned, kindly agreed to let me take a stab at it (thanks!).

The approach I took was to normalize the path by replacing each of os.sep and os.altsep with slashes if (a) these characters are present in the path component and (b) the operating system is such that os.sep or os.altsep != '/'. (Currently, os.altsep is either None or '/' on all systems, but it seemed like a good idea to check anyway.)

Requesting a relative path which, when translated, would point above the current working directory (e.g. http://localhost:8000/../) causes the server to return a 400 error, which is just how Apache responds to such requests.

Internal calls to translate_path with such malformed paths cause translate_path to raise an IndexError, which is consistent with how _url_collapse_path_split (used by CGIRequestHandler) handles them.
msg138226 - (view) Author: Ori Livneh (ori.livneh) * Date: 2011-06-13 00:58
I updated the patch, making the emendations suggested by Eric's review, and making a few additional changes. I was bothered that translate_path was duplicating functionality from _url_collapse_path_split, so I made some corrections to the latter and rewrote translate_path so that it uses _url_collapse_path_split and implements only the checks necessary for translating the path to a path on the local file system path.

translate_path relies on os.path to make sure the path is safe, which is (I think) also the proper way to do things, since it's not good to have to remember to update path semantics in http.server if Python is ported to additional platforms.

I also read the various specs and made sure entities are unquoted at the appropriate point.
msg138568 - (view) Author: Senthil Kumaran (orsenthil) * (Python committer) Date: 2011-06-18 07:24
Ori, which platform did you try to reproduce this issue. I tried in all active codelines (cpython to all through 2.5) from hg and can't able to reproduce this bug on Linux. If someone can reproduce, can you provide exact instructions.
msg139052 - (view) Author: engelbert gruber (grubert) * Date: 2011-06-25 13:00
SimpleHTTPServer does not exist in Python3.1 up instead http.server.

All versions (3.x 2011-06-25) reply the contents from the served directory on a request of the upper directory and act similar with files.

Maybe documentation needs an update documentation.
msg139056 - (view) Author: engelbert gruber (grubert) * Date: 2011-06-25 13:06
My test setup:

  test.html
  2.5/test.html
  2.7/test.html

in 2.5 and 2.7 execute ::

  python.exe -m SimpleHTTPServer 8000

``http://localhost:8000/../`` shows the contents of the ``2.x`` directory.

``http://localhost:8000/../test.html`` shows the contents of the file in the ``2.x`` directory not the one in the upper.

Should be closed.
msg139223 - (view) Author: Senthil Kumaran (orsenthil) * (Python committer) Date: 2011-06-26 21:07
The module documentation for the SimpleHTTPServer class says that.

"""

   This class serves files from the current directory and below, directly
   mapping the directory structure to HTTP requests.

"""

As it is already documented. Nothing else needs to be done for this report. Closing this one. Thanks!
msg139554 - (view) Author: Huzaifa Sidhpurwala (Huzaifa.Sidhpurwala) Date: 2011-07-01 08:26
It seems python was being blamed for what is essentially the fault of lynx.

The following would translate into browsing files locally from the system and not from the web:

lynx http://localhost:8000/../../../../../../../../etc/passwd

The correct syntax for testing should have been:

lynx http://localhost:8000/../../../../../../../../etc/passwd
msg139556 - (view) Author: Huzaifa Sidhpurwala (Huzaifa.Sidhpurwala) Date: 2011-07-01 08:35
This should have been

lynx localhost:8000/../../../../../../../../etc/passwd

v/s

lynx http://localhost:8000/../../../../../../../../etc/passwd
msg140774 - (view) Author: Ori Livneh (ori.livneh) * Date: 2011-07-21 00:13
Yes, I seem to have gotten confused about this. Sorry for the confusion, and thanks for clearing it up.
History
Date User Action Args
2011-07-21 00:13:25ori.livnehsetmessages: + msg140774
2011-07-01 08:35:01Huzaifa.Sidhpurwalasetmessages: + msg139556
2011-07-01 08:26:49Huzaifa.Sidhpurwalasetnosy: + Huzaifa.Sidhpurwala
messages: + msg139554
2011-06-26 21:07:45orsenthilsetstatus: open -> closed
resolution: not a bug
messages: + msg139223

stage: needs patch -> resolved
2011-06-25 13:26:13grubertsetnosy: + rhettinger
2011-06-25 13:06:53grubertsetmessages: + msg139056
2011-06-25 13:00:52grubertsetnosy: + grubert

messages: + msg139052
versions: - Python 3.1, Python 3.2, Python 3.3
2011-06-18 07:24:31orsenthilsetmessages: + msg138568
2011-06-13 00:58:57ori.livnehsetfiles: + translate_path_rev2.patch

messages: + msg138226
2011-06-06 02:11:15ori.livnehsetfiles: + translate_path.patch
keywords: + patch
messages: + msg137726
2011-06-06 01:53:34ori.livnehsetnosy: + ori.livneh
2011-06-03 15:18:42eric.araujosetnosy: + eric.araujo
2011-06-01 01:43:42jconsetnosy: + jcon
2011-05-17 03:18:47orsenthilsetassignee: orsenthil

nosy: + orsenthil
2011-05-15 22:57:27gregory.p.smithsetassignee: gregory.p.smith -> (no value)
messages: + msg136054
2011-02-24 12:21:57asdfasdfasdfasdfasdfasdfasdfsetnosy: + asdfasdfasdfasdfasdfasdfasdf
messages: + msg129260
2011-02-13 09:46:36georg.brandlsetpriority: deferred blocker -> critical
nosy: barry, brett.cannon, georg.brandl, gregory.p.smith, gps, benjamin.peterson, Arfrever, dmalcolm
messages: + msg128483
2011-02-13 05:42:12gregory.p.smithsetnosy: barry, brett.cannon, georg.brandl, gregory.p.smith, gps, benjamin.peterson, Arfrever, dmalcolm
messages: + msg128480
versions: - Python 2.5
2011-02-12 07:31:29georg.brandlsetpriority: release blocker -> deferred blocker
nosy: barry, brett.cannon, georg.brandl, gregory.p.smith, gps, benjamin.peterson, Arfrever, dmalcolm
messages: + msg128439
2011-02-12 02:55:22gregory.p.smithsetassignee: gregory.p.smith

nosy: + gregory.p.smith
2011-02-11 19:42:45Arfreversetnosy: + Arfrever
2011-02-11 19:36:56dmalcolmsetnosy: barry, brett.cannon, georg.brandl, gps, benjamin.peterson, dmalcolm
messages: + msg128423
2011-02-11 18:46:00brett.cannoncreate