0x00 前言
早前发现boooom在乌云上发了很多个任意文件读取的漏洞,都是形如
http://target/../../../../etc/passwd
这样。当时感觉很新奇,因为正常情况下,通常的服务器中间件是不允许直接读取web目录以外的文件的,为什么这样的漏洞却出现在了很多案例中。
后来lijiejie在安全脉搏的文章给出了解释:关于python和django的目录遍历漏洞(任意文件读取) or 李姐姐博客,原来是python这种新型web开发方式造成的问题。
然后翻了下我自己以前用web.py、tornado开发的一些应用,果然也存在这样的问题。
这个问题就像lijiejie说的那样,一方面是低版本django框架自身的一些漏洞,另一方面,就是开发者自身的疏忽造成的问题。
这不得不提到现今开发框架与以前的一些区别。不管是python还是node、ruby的框架,都是一个可以自定义URL分配的框架,不再是像php或asp中那样根据目录结构来请求文件。所有的请求由用户定义规则,而框架内核部分解析、配发、执行。比如我们请求的“/login/”这个URL,很可能是被配发给一个LoginHandler类去处理了,而不是请求到/login/index.php上。
这时候造成了一个问题,如果我们就是想去请求一个真实的文件,比如css、js等静态文件,怎么办?
一般也会有一些区分,一些要求比较高的应用,多是采用了CDN缓存或负载均衡,nginx作为负载分配的处理器。当发现我们请求的url是一个静态文件的话,就直接由CDN或nginx返回相应文件。如下图:
那么这之中也存在这一个定义问题,什么请求才说明是要请求“静态文件”?只要以.css、.js结尾就可以吗?当然这也是一种方法,但一般应用会定义一个目录,如/static/,所有请求匹配“/static/(.*)”的会被认为是静态文件,所以开发者一般将静态文件放在这个目录下,我们用户就能够直接请求到他了。
如果不存在CDN、nginx等平台,其实类似web.py、tornado这样的框架自己也定义了静态目录,在web.py下,默认的静态目录都是/static/,也就是在这个目录下的请求是不会经过URLPath的。如web.py文档中说到的:
这时候,我就会有这个思考,框架内部如果是以/static/(.*)来匹配请求的话,如果我们求
/static/../../../../../etc/passwd
是不是就可以读取到/etcs/passwd文件?
0x01 web.py下可能的任意文件读取漏洞研究
我们先来看看web.py是怎样处理这种请求的:
/static/../../../../../etc/passwd
我们在web/httpserver.py中可以看到这样的代码:
def do_GET(self):
if self.path.startswith('/static/'):
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
else:
self.run_wsgi_app()
当请求以/static/开头的话,就直接交给SimpleHTTPServer处理了。SimpleHTTPServer是python自带的一个简单的HTTP Server