Lucene search

K
seebugRootSSV:92944
HistoryApr 13, 2017 - 12:00 a.m.

Django.views.static.serve url跳转漏洞(CVE-2017-7234)

2017-04-1300:00:00
Root
www.seebug.org
67

0.002 Low

EPSS

Percentile

52.5%

来源:同程安全应急响应中心
作者:Nearg1e@YSRC

来自 @Phithon 的一个漏洞。

问题出现在:django.views.static.serve()函数上。该函数可以用来指定web站点的静态文件目录。如:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^staticp/(?P<path>.*)$', serve, {'document_root': os.path.join(settings.BASE_DIR, 'staticpath')})
]

这样django项目根目录下staticpath中的所有文件,就可以在staticp/目录中访问。e.g. http://127.0.0.1:8000/staticp/test.css

这种方法是不被django官方推荐在生成环境使用的,对安全性和性能都有一定影响。

问题代码如下 (django/views/static.py):

path = posixpath.normpath(unquote(path))
path = path.lstrip('/')
newpath = ''
for part in path.split('/'):
    if not part:
        ### Strip empty path components.
        continue
    drive, part = os.path.splitdrive(part)
    head, part = os.path.split(part)
    if part in (os.curdir, os.pardir):
        ### Strip '.' and '..' in path.
        continue
    newpath = os.path.join(newpath, part).replace('\\', '/')
if newpath and path != newpath:
    return HttpResponseRedirect(newpath)

path既我们传入的路径,如果传入的路径为 staticp/path.css ,则path=path.css 。跟踪代码可知,path经过了unquote进行url解码,后来又 replace('\\', '/'),进入HttpResponseRedirect,很诡异的逻辑看起来很有问题。一般遇到这类型的函数我们会先试着找看看,任意文件读漏洞,但是这个对’.’和’…’进行了过滤,所以这边这个HttpResponseRedirect函数就成了帅的人的目标。

我们的最终目的是 HttpResponseRedirect('//evil.neargle.com')
或者 HttpResponseRedirect('http://evil.neargle.com'),那么就要使 path != newpath,那么path里面就必须带有’\‘,好的现在的我们传入 ’/staticp/%5C%5Cblog.neargle.com’ ,则path=’\\blog.neargle.com’,newpath=’//blog.neargle.com’,HttpResponseRedirect 就会跳转到 ’blog.neargle.com’ 造成跳转漏洞。

修复

嗯,官方表示自己也不知道为什么要写这串代码,删了这一串代码然后用safe_url函数代替。