Skip to content

Commit

Permalink
Prevent directory traversal attacks
Browse files Browse the repository at this point in the history
  • Loading branch information
beavailable committed Oct 5, 2022
1 parent c1de43f commit 072f1b1
Showing 1 changed file with 28 additions and 24 deletions.
52 changes: 28 additions & 24 deletions share.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ def handle_multipart(self, save_dir, redirect_location):
else:
self.respond_redirect(redirect_location)

def handle_putfile(self, save_dir):
filename = os.path.basename(parse.unquote(self.path))
def handle_putfile(self, file_path):
content_length = self.get_content_length()
if not content_length:
self.respond_bad_request()
Expand All @@ -150,8 +149,8 @@ def handle_putfile(self, save_dir):
self.respond_internal_server_error()
return
try:
os.makedirs(save_dir, exist_ok=True)
with open(f'{save_dir}/{filename}', 'wb') as f:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'wb') as f:
while content_length:
l = min(content_length, 65536)
f.write(self.rfile.read(l))
Expand Down Expand Up @@ -214,6 +213,20 @@ def _parse_boundary(self, content_type):
return None
return value

def _split_path(self, path):
path, _, query = path.partition('?')
path = parse.unquote(path)
parts = []
for p in path.split('/'):
if p == '..':
parts.pop()
elif p and p != '.':
parts.append(p)
collapsed_path = '/' + '/'.join(parts)
if path != '/' and path.endswith('/'):
collapsed_path += '/'
return (collapsed_path, query)

def send_content_length(self, content_length):
self.send_header('Content-Length', str(content_length))

Expand Down Expand Up @@ -328,20 +341,6 @@ def __init__(self, *args, upload=False, **kwargs):
self.is_hidden = self._is_hidden_unix
super().__init__(*args, **kwargs)

def split_path(self, path):
path, _, query = path.partition('?')
path = parse.unquote(path)
parts = []
for p in path.split('/'):
if p == '..':
parts.pop()
elif p and p != '.':
parts.append(p)
collapsed_path = '/' + '/'.join(parts)
if path != '/' and path.endswith('/'):
collapsed_path += '/'
return (collapsed_path, query)

def respond_for_file(self, file):
include_content_disposition = self._is_from_commandline()
try:
Expand Down Expand Up @@ -647,7 +646,7 @@ def __init__(self, files, *args, **kwargs):

def do_get(self):
try:
path, _ = self.split_path(self.path)
path, _ = self._split_path(self.path)
except IndexError:
self.respond_bad_request()
return
Expand Down Expand Up @@ -689,7 +688,7 @@ def __init__(self, dir, all, *args, **kwargs):

def do_get(self):
try:
path, _ = self.split_path(self.path)
path, _ = self._split_path(self.path)
except IndexError:
self.respond_bad_request()
return
Expand Down Expand Up @@ -725,7 +724,7 @@ def do_get(self):
def do_post(self):
if self._upload:
try:
path, _ = self.split_path(self.path)
path, _ = self._split_path(self.path)
except IndexError:
self.respond_bad_request()
return
Expand All @@ -736,11 +735,11 @@ def do_post(self):
def do_put(self):
if self._upload:
try:
path, _ = self.split_path(self.path)
path, _ = self._split_path(self.path)
except IndexError:
self.respond_bad_request()
return
self.handle_putfile(self._dir.rstrip('/') + os.path.dirname(path))
self.handle_putfile(self._dir.rstrip('/') + path)
else:
super().do_put()

Expand Down Expand Up @@ -898,7 +897,12 @@ def do_post(self):
self.handle_multipart(self._dir, '/')

def do_put(self):
self.handle_putfile(self._dir.rstrip('/') + os.path.dirname(parse.unquote(self.path)))
try:
path, _ = self._split_path(self.path)
except IndexError:
self.respond_bad_request()
return
self.handle_putfile(self._dir.rstrip('/') + path)


class TextShareHandler(BaseHandler):
Expand Down

0 comments on commit 072f1b1

Please sign in to comment.