This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author Thomas
Recipients Thomas
Date 2016-03-28.15:30:14
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1459179015.77.0.509336394494.issue26657@psf.upfronthosting.co.za>
In-reply-to
Content
SimpleHTTPServer and http.server allow directory traversal on Windows.
To exploit this vulnerability, replace all ".." in URLs with "c:c:c:..".


Example:
Run
python -m http.server
and visit
127.0.0.1:8000/c:c:c:../secret_file_that_should_be_secret_but_is_not.txt


There is a warning that those modules are not secure in the module docs,
but for some reason they do not appear in the online docs:
https://docs.python.org/3/library/http.server.html
https://docs.python.org/2/library/simplehttpserver.html


It would be nice if that warning was as apparent as for example here:
https://docs.python.org/2/library/xml.etree.elementtree.html


There are a lot of other URLs that are insecure as well, which can all
be traced back to here:
https://hg.python.org/cpython/file/tip/Lib/http/server.py#l766


The splitdrive and split functions, which should make sure that the
final output is free of ".." are only called once which leads to this
control flow:
---------------------------------------------------------------
path = "c:/secret/public"
word = "c:c:c:.."

_, word = os.path.splitdrive(word) # word = "c:c:.."
_, word = os.path.split(word) # word = "c:.."
path = os.path.join(path, word) # path = "c:/secret/public\\.."
---------------------------------------------------------------


Iterating splitdrive and split seems safer:
---------------------------------------------------------------
for word in words:
    # Call split and splitdrive multiple times until
    # word does not change anymore.
    has_changed = True
    while has_changed:
        previous_word = word
        _, word = os.path.split(word)
        _, word = os.path.splitdrive(word)
        has_changed = word != previous_word
---------------------------------------------------------------






There is another weird thing which I am not quite sure about here:
https://hg.python.org/cpython/file/tip/Lib/http/server.py#l761

---------------------------------------------------------------
path = posixpath.normpath(path)
words = path.split('/')
---------------------------------------------------------------

posixpath.normpath does not do anything with backslashes and then the
path is split by forward slashes, so it may still contain backslashes.
Maybe replacing posixpath.normpath with os.path.normpath and then
splitting by os.sep would work, but I don't have enough different
operating systems to test this, so someone else should have a look.





I have attached some simple fuzzing test that tries a few weird URLs and
sees if they lead where they shouldn't.
Disclaimer: Might still contain other bugs.
History
Date User Action Args
2016-03-28 15:30:15Thomassetrecipients: + Thomas
2016-03-28 15:30:15Thomassetmessageid: <1459179015.77.0.509336394494.issue26657@psf.upfronthosting.co.za>
2016-03-28 15:30:15Thomaslinkissue26657 messages
2016-03-28 15:30:15Thomascreate