mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 00:52:16 -06:00
fix path traversal ( ´_ゝ`)
This commit is contained in:
parent
af28a90e3d
commit
5414591362
|
@ -6,6 +6,7 @@ import os
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from .__init__ import *
|
from .__init__ import *
|
||||||
|
from .util import undot
|
||||||
|
|
||||||
|
|
||||||
class VFS(object):
|
class VFS(object):
|
||||||
|
@ -49,24 +50,9 @@ class VFS(object):
|
||||||
self.nodes[dst] = vn
|
self.nodes[dst] = vn
|
||||||
return vn
|
return vn
|
||||||
|
|
||||||
def undot(self, path):
|
|
||||||
ret = []
|
|
||||||
for node in path.split("/"):
|
|
||||||
if node in ["", "."]:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if node == "..":
|
|
||||||
if ret:
|
|
||||||
ret.pop()
|
|
||||||
continue
|
|
||||||
|
|
||||||
ret.append(node)
|
|
||||||
|
|
||||||
return "/".join(ret)
|
|
||||||
|
|
||||||
def _find(self, vpath):
|
def _find(self, vpath):
|
||||||
"""return [vfs,remainder]"""
|
"""return [vfs,remainder]"""
|
||||||
vpath = self.undot(vpath)
|
vpath = undot(vpath)
|
||||||
if vpath == "":
|
if vpath == "":
|
||||||
return [self, ""]
|
return [self, ""]
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,16 @@ class HttpCli(object):
|
||||||
def __init__(self, conn):
|
def __init__(self, conn):
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
self.s = conn.s
|
self.s = conn.s
|
||||||
|
self.sr = conn.sr
|
||||||
self.addr = conn.addr
|
self.addr = conn.addr
|
||||||
self.args = conn.args
|
self.args = conn.args
|
||||||
self.auth = conn.auth
|
self.auth = conn.auth
|
||||||
|
|
||||||
self.sr = conn.sr
|
|
||||||
self.bufsz = 1024 * 32
|
|
||||||
self.ok = True
|
|
||||||
|
|
||||||
self.log_func = conn.log_func
|
self.log_func = conn.log_func
|
||||||
self.log_src = conn.log_src
|
self.log_src = conn.log_src
|
||||||
|
|
||||||
|
self.ok = True
|
||||||
|
self.bufsz = 1024 * 32
|
||||||
|
|
||||||
def log(self, msg):
|
def log(self, msg):
|
||||||
self.log_func(self.log_src, msg)
|
self.log_func(self.log_src, msg)
|
||||||
|
|
||||||
|
@ -42,13 +41,12 @@ class HttpCli(object):
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.headers = {}
|
|
||||||
try:
|
try:
|
||||||
mode, self.req, _ = headerlines[0].split(" ")
|
mode, self.req, _ = headerlines[0].split(" ")
|
||||||
except:
|
except:
|
||||||
self.log("bad headers:\n" + "\n".join(headerlines))
|
raise Pebkac("bad headers:\n" + "\n".join(headerlines))
|
||||||
return False
|
|
||||||
|
|
||||||
|
self.headers = {}
|
||||||
for header_line in headerlines[1:]:
|
for header_line in headerlines[1:]:
|
||||||
k, v = header_line.split(":", 1)
|
k, v = header_line.split(":", 1)
|
||||||
self.headers[k.lower()] = v.strip()
|
self.headers[k.lower()] = v.strip()
|
||||||
|
@ -61,23 +59,34 @@ class HttpCli(object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
v = unescape_cookie(v)
|
v = unescape_cookie(v)
|
||||||
if v == "x":
|
if v in self.auth.iuser:
|
||||||
break
|
|
||||||
|
|
||||||
if not v in self.auth.iuser:
|
|
||||||
msg = u'bad_cpwd "{}"'.format(v)
|
|
||||||
nuke = u"Set-Cookie: cppwd=x; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"
|
|
||||||
self.loud_reply(msg, headers=[nuke])
|
|
||||||
return True
|
|
||||||
|
|
||||||
self.uname = self.auth.iuser[v]
|
self.uname = self.auth.iuser[v]
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
if self.uname:
|
if self.uname:
|
||||||
self.rvol = self.auth.vfs.user_tree(self.uname, readable=True)
|
self.rvol = self.auth.vfs.user_tree(self.uname, readable=True)
|
||||||
self.wvol = self.auth.vfs.user_tree(self.uname, writable=True)
|
self.wvol = self.auth.vfs.user_tree(self.uname, writable=True)
|
||||||
self.log(self.rvol)
|
self.log(self.rvol)
|
||||||
self.log(self.wvol)
|
self.log(self.wvol)
|
||||||
|
|
||||||
|
# split req into vpath + args
|
||||||
|
args = {}
|
||||||
|
if not "?" in self.req:
|
||||||
|
vpath = undot(self.req)
|
||||||
|
else:
|
||||||
|
vpath, arglist = self.req.split("?", 1)
|
||||||
|
vpath = undot(vpath)
|
||||||
|
for k in arglist.split("&"):
|
||||||
|
if "=" in k:
|
||||||
|
k, v = k.split("=", 1)
|
||||||
|
args[k.lower()] = v.strip()
|
||||||
|
else:
|
||||||
|
args[k.lower()] = True
|
||||||
|
|
||||||
|
self.args = args
|
||||||
|
self.vpath = vpath
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if mode == "GET":
|
if mode == "GET":
|
||||||
self.handle_get()
|
self.handle_get()
|
||||||
|
@ -116,43 +125,28 @@ class HttpCli(object):
|
||||||
self.log("GET " + self.req)
|
self.log("GET " + self.req)
|
||||||
|
|
||||||
# "embedded" resources
|
# "embedded" resources
|
||||||
if self.req.startswith("/.cpr/"):
|
if self.vpath.startswith(u".cpr"):
|
||||||
static_path = os.path.join(E.mod, "web", self.req.split("?")[0][6:])
|
static_path = os.path.join(E.mod, "web/", self.vpath[5:])
|
||||||
|
|
||||||
if os.path.isfile(static_path):
|
if os.path.isfile(static_path):
|
||||||
return self.tx_file(static_path)
|
return self.tx_file(static_path)
|
||||||
|
|
||||||
# split req into vpath + args
|
|
||||||
args = {}
|
|
||||||
vpath = self.req[1:]
|
|
||||||
if "?" in vpath:
|
|
||||||
vpath, arglist = vpath.split("?", 1)
|
|
||||||
for k in arglist.split("&"):
|
|
||||||
if "=" in k:
|
|
||||||
k, v = k.split("=", 1)
|
|
||||||
args[k.lower()] = v.strip()
|
|
||||||
else:
|
|
||||||
args[k.lower()] = True
|
|
||||||
|
|
||||||
# conditional redirect to single volumes
|
# conditional redirect to single volumes
|
||||||
if vpath == "" and not args:
|
if self.vpath == "" and not self.args:
|
||||||
nread = len(self.rvol)
|
nread = len(self.rvol)
|
||||||
nwrite = len(self.wvol)
|
nwrite = len(self.wvol)
|
||||||
if nread + nwrite == 1:
|
if nread + nwrite == 1:
|
||||||
if nread == 1:
|
if nread == 1:
|
||||||
vpath = self.rvol[0]
|
self.vpath = self.rvol[0]
|
||||||
else:
|
else:
|
||||||
vpath = self.wvol[0]
|
self.vpath = self.wvol[0]
|
||||||
|
|
||||||
# go home if verboten
|
# go home if verboten
|
||||||
readable = vpath in self.rvol
|
readable = self.vpath in self.rvol
|
||||||
writable = vpath in self.wvol
|
writable = self.vpath in self.wvol
|
||||||
if not readable and not writable:
|
if not readable and not writable:
|
||||||
self.log("inaccessible: {}".format(vpath))
|
self.log("inaccessible: {}".format(self.vpath))
|
||||||
args = {"h"}
|
self.args = {"h": True}
|
||||||
|
|
||||||
self.vpath = vpath
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
if "h" in self.args:
|
if "h" in self.args:
|
||||||
self.vpath = None
|
self.vpath = None
|
||||||
|
@ -190,12 +184,17 @@ class HttpCli(object):
|
||||||
|
|
||||||
def handle_login(self):
|
def handle_login(self):
|
||||||
pwd = self.parser.require("cppwd", 64)
|
pwd = self.parser.require("cppwd", 64)
|
||||||
if not pwd in self.auth.iuser:
|
self.parser.drop()
|
||||||
h = [u"Set-Cookie: cppwd=x; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
|
|
||||||
self.loud_reply(u'bad_ppwd "{}"'.format(pwd), headers=h)
|
if pwd in self.auth.iuser:
|
||||||
|
msg = u"login ok"
|
||||||
else:
|
else:
|
||||||
|
msg = u"naw dude"
|
||||||
|
pwd = u"x"
|
||||||
|
|
||||||
h = ["Set-Cookie: cppwd={}; Path=/".format(pwd)]
|
h = ["Set-Cookie: cppwd={}; Path=/".format(pwd)]
|
||||||
self.loud_reply(u"login_ok", headers=h)
|
html = u'<h1>{}<h2><a href="/">ack'.format(msg)
|
||||||
|
self.reply(html.encode("utf-8"), headers=h)
|
||||||
|
|
||||||
def handle_plain_upload(self):
|
def handle_plain_upload(self):
|
||||||
nullwrite = self.args.nw
|
nullwrite = self.args.nw
|
||||||
|
|
|
@ -264,6 +264,22 @@ def read_header(sr):
|
||||||
return ret[:-4].decode("utf-8", "replace").split("\r\n")
|
return ret[:-4].decode("utf-8", "replace").split("\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
def undot(path):
|
||||||
|
ret = []
|
||||||
|
for node in path.split(u"/"):
|
||||||
|
if node in [u"", u"."]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if node == u"..":
|
||||||
|
if ret:
|
||||||
|
ret.pop()
|
||||||
|
continue
|
||||||
|
|
||||||
|
ret.append(node)
|
||||||
|
|
||||||
|
return u"/".join(ret)
|
||||||
|
|
||||||
|
|
||||||
def sanitize_fn(fn):
|
def sanitize_fn(fn):
|
||||||
return fn.replace("\\", "/").split("/")[-1].strip()
|
return fn.replace("\\", "/").split("/")[-1].strip()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue