2

I have created a simple http server for my family on the local network, when i add a html file and png picture and tried to view the HTML file, my image cannot load.
It says:
"The image “http://...:255/header.png” cannot be displayed because it contains errors."
Here is a bit of my code

        elif self.path.endswith(".bm"):   #our dynamic content
            self.send_response(200)
            self.send_header('Content-type',    'text/html')
            self.end_headers()
            f= open(curdir + sep + self.path)
            ren = self.render(f.read())
            self.wfile.write(ren)
            return
        elif self.path.endswith('.png'):
            print "IMAGE WANTED!"
            self.send_response(200)
            self.send_header('Content-type',    'image/png')
            self.end_headers()
            f = open(curdir + sep + self.path)
            self.wfile.write(f.read())
            return
        elif self.path.endswith('.jpg'):
            print "IMAGE WANTED!"
            self.send_response(200)
            self.send_header('Content-type',    'image/jpeg')
            self.end_headers()
            f= open(curdir + sep + self.path)
            print f.read()
            self.wfile.write(f.read())
            return
        elif self.path.endswith(".esp"):
            self.send_response(200)
            self.send_header('Content-type',    'text/plain')
            self.end_headers()
            self.wfile.write("This Format Is Not Supported Any More, Upgrade To BM Script")
            return

They all work except for the png and jpeg section. BM script I made myself, same with esp so that is just nothing

2
  • 2
    Please tell me this will never be reachable from the internet, because you will have a wide security hole open there (you allow relative paths like ../../../etc/passwd\0) Commented Jan 6, 2012 at 1:09
  • 5
    Why don't you just use the built-in python -m SimpleHTTPServer. This will serve up the current directory. Commented Jan 6, 2012 at 1:21

1 Answer 1

7

The default mode of open is 'r', which stands for reading text data and does automatic EOL conversion on Windows. Replace f = open(curdir + sep + self.path); self.wfile.write(f.read()) with

fn = os.path.normpath(os.path.join(curdir, self.path))
if not fn.startswith(abspath + os.path.sep):
    raise Exception('Path traversal attempt')
with open(fn, 'rb') as f:
    self.wfile.write(f.read())

The with statement fixes the leak of file handles. Alternatively (on Python < 2.5), you can call f.close() manually.

os.path.join (for which you may need to import os.path at the beginning of the file) is a cleaner filename construction mechanism than string concatenation. The check that the resulting filename is in the directory you expect prevents the path traversal vulnerability that would allow anyone to read all the files on your system.

Sign up to request clarification or add additional context in comments.

7 Comments

I may be missing something, but how does normpath prevent path traversal? My understanding is that it only "normalizes" a path, basically just cleaning it up. A//B, A/B/, A/./B and A/foo/../B all become A/B.
@monkut - You use normpath to join the web root with the user path and then ensure it actually starts with the webroot: import os; root = "/web/root"; path_from_client = "../../etc/passwd"; os.path.normpath(os.path.join(root, path_from_client)).startswith(root)
@jdi that makes sense, but it doesn't appear to be clear in the answer here. The call to normpath alone does not protect you from path traversal.
import os is enough to call functions from os.path. You certainly shouldn't do import os.path.join as that ends with an ImportError: No module named join error.
@monkut @jdi Yeah, you're right. Corrected. Note that just testing for startswith(root) is still wrong, since it allows paths like '/path/to/root_backup/'.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.