当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-098978

漏洞标题:Python开源框架Tornado某缺陷可能造成文件读取漏洞

相关厂商:Tornado开源框架

漏洞作者: phith0n

提交时间:2015-03-01 21:54

修复时间:2015-06-04 08:38

公开时间:2015-06-04 08:38

漏洞类型:设计错误/逻辑缺陷

危害等级:中

自评Rank:8

漏洞状态:已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-03-01: 细节已通知厂商并且等待厂商处理中
2015-03-06: 厂商已经确认,细节仅向厂商公开
2015-03-09: 细节向第三方安全合作伙伴开放
2015-04-30: 细节向核心白帽子及相关领域专家公开
2015-05-10: 细节向普通白帽子公开
2015-05-20: 细节向实习白帽子公开
2015-06-04: 细节向公众公开

简要描述:

python开源框架Tornado的一个缺陷,可能造成一些不能被读取的文件被读取。

详细说明:

最近在筹备写一篇关于“任意文件读取”的文章。。。没想到写文章的过程中发现tornado的一个小问题,提出来希望引起大家的重视。
首先,tornado是一个全异步的框架,它有有一个专门处理静态文件的控制器,名字叫StaticFileHandler,在文档(http://www.tornadoweb.org/en/stable/web.html#tornado.web.Application)中可以得知:

QQ20150301-8@2x.png


我们只要指定一个目录对应到这个控制器中,即可在HTTP请求中直接请求到这个目录下的文件。
而且,tornado在setting中,也可以直接指定一个static_path,来说明静态文件放在哪个目录下:

QQ20150301-9@2x.png


那么我们直接吧example拿来,增加一个static_path的设置项:

#!/usr/bin/python
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
if __name__ == "__main__":
setting = {
"debug": True,
"static_path": "/Users/phithon/pro/python/wooyun/tornado-file-read/static/",
}
application = tornado.web.Application([
(r"/", MainHandler),
], **setting)
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()


这时候我们就可以直接请求到/static/01.txt这样的静态文件了:

QQ20150301-10@2x.png


正常情况下,我们是不能够请求到这个目录以外的文件的,如/etc/passwd:

QQ20150301-11@2x.png


如上图,tornado对请求的路径进行了一定判断,抛出了这个错误。然后我们去他源码中看看是怎么判断的:

def validate_absolute_path(self, root, absolute_path):
"""Validate and return the absolute path.
``root`` is the configured path for the `StaticFileHandler`,
and ``path`` is the result of `get_absolute_path`
This is an instance method called during request processing,
so it may raise `HTTPError` or use methods like
`RequestHandler.redirect` (return None after redirecting to
halt further processing). This is where 404 errors for missing files
are generated.
This method may modify the path before returning it, but note that
any such modifications will not be understood by `make_static_url`.
In instance methods, this method's result is available as
``self.absolute_path``.
.. versionadded:: 3.1
"""
root = os.path.abspath(root)
# os.path.abspath strips a trailing /
# it needs to be temporarily added back for requests to root/
if not (absolute_path + os.path.sep).startswith(root):
raise HTTPError(403, "%s is not in root static directory",
self.path)
if (os.path.isdir(absolute_path) and
self.default_filename is not None):
# need to look at the request.path here for when path is empty
# but there is some prefix to the path that was already
# trimmed by the routing
if not self.request.path.endswith("/"):
self.redirect(self.request.path + "/", permanent=True)
return
absolute_path = os.path.join(absolute_path, self.default_filename)
if not os.path.exists(absolute_path):
raise HTTPError(404)
if not os.path.isfile(absolute_path):
raise HTTPError(403, "%s is not a file", self.path)
return absolute_path


关键代码是
root = os.path.abspath(root),
if not (absolute_path + os.path.sep).startswith(root):
os.path.abspath获取root变量指定的绝对路径。
root实际上就是我们之前传入的setting中的“static_path”,这里获得静态文件目录的绝对路径。但在python中,os.path.abspath这个函数获得的路径,是没有结尾处的"/"的。
也就是说,我传入的路径是“/Users/phithon/pro/python/wooyun/tornado-file-read/static/”,经过这个函数处理,变成了“/Users/phithon/pro/python/wooyun/tornado-file-read/static”。
好,接下来这个if语句,absolute_path + os.path.sep就是我请求的静态文件路径,一旦它不是以root开头的话,就会爆403错误。
我们想想可能会出现什么漏洞?
因为root这个变量是没有最后那个“/“的,那么如果我有一个文件是“/Users/phithon/pro/python/wooyun/tornado-file-read/static.db”,或一个目录是“/Users/phithon/pro/python/wooyun/tornado-file-read/static_private/”,那是不是都以“/Users/phithon/pro/python/wooyun/tornado-file-read/static”开头的?但这些文件并不在static这个目录下,所以并没有触发403错误。
这种情况下造成了一个文件读取漏洞,我们读取到了本不应该被读取的某些文件。
举个例子吧,有这么一个应用(下载链接: http://pan.baidu.com/s/1dD6cLWH 密码: gal2),如下是目录结构:

QQ20150301-12@2x.png


有一个数据库叫static_private.sqlite3,有个目录叫static_private,里面放着敏感信息私钥private.key。
我们通过如下请求把他们都读取了:

QQ20150301-13@2x.png


QQ20150301-14@2x.png


所以在特殊情况下,如果开发者指定的静态目录为xxx,那么我们就可以读取所有xxx上层的目录下的名字开头为xxx的文件、目录。
这个其实和设置open_basedir的时候没有带最后一个“/”产生的效果类似。

漏洞证明:

QQ20150301-13@2x.png


QQ20150301-14@2x.png

修复方案:

root = os.path.abspath(root) + os.path.sep

版权声明:转载请注明来源 phith0n@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2015-03-06 08:36

厂商回复:

先行确认,暂未能通过实例完整复现,同时也未能建立与软件生产厂商的联系渠道.

最新状态:

暂无


漏洞评价:

评论

  1. 2015-03-01 22:10 | 猪猪侠 认证白帽子 ( 核心白帽子 | Rank:3224 漏洞数:254 | 你都有那么多超级棒棒糖了,还要自由干吗?)

    关注

  2. 2015-03-01 22:36 | phith0n 认证白帽子 ( 核心白帽子 | Rank:656 漏洞数:107 | 一个想当文人的黑客~)

    @猪猪侠 能被猪猪侠关注此生足矣呀足矣

  3. 2015-03-01 22:38 | 浅蓝 ( 普通白帽子 | Rank:274 漏洞数:109 | 爱安全:www.ixsec.orgXsec社区:zone.ixse...)

    膜拜洞主

  4. 2015-03-01 22:49 | todaro ( 实习白帽子 | Rank:39 漏洞数:12 | 完结。)

    这个吊

  5. 2015-03-01 23:09 | ki11y0u ( 普通白帽子 | Rank:104 漏洞数:23 | 好好学习,求带飞~~~~~~~~~~~~~~~~~~~~~~...)

    膜拜洞主

  6. 2015-03-01 23:13 | 泳少 ( 普通白帽子 | Rank:231 漏洞数:79 | ★ 梦想这条路踏上了,跪着也要...)

    关注

  7. 2015-03-02 00:07 | Samsong ( 路人 | Rank:0 漏洞数:1 | Student.)

    膜拜核心

  8. 2015-03-02 00:14 | f4ckbaidu ( 普通白帽子 | Rank:182 漏洞数:23 | 开发真是日了狗了)

    牛逼,天天搞框架

  9. 2015-03-02 00:21 | _Thorns ( 普通白帽子 | Rank:882 漏洞数:157 | 收wb 1:5 无限量收 [平台担保]))

    关注之,学习。

  10. 2015-03-02 00:51 | _Thorns ( 普通白帽子 | Rank:882 漏洞数:157 | 收wb 1:5 无限量收 [平台担保]))

    不会和Django的那个是一样的把?

  11. 2015-03-02 00:53 | dangge ( 路人 | Rank:1 漏洞数:1 | 菜鸟一枚 努力学习中。)

    关注

  12. 2015-03-02 01:23 | Ricter ( 实习白帽子 | Rank:59 漏洞数:15 | 渣渣一个)

    Windows only?而且需要条件限制?

  13. 2015-03-02 01:46 | phith0n 认证白帽子 ( 核心白帽子 | Rank:656 漏洞数:107 | 一个想当文人的黑客~)

    @Ricter @_Thorns 只是一种情况存在文件读取可能,不一样。

  14. 2015-03-02 08:00 | 啊L川 ( 普通白帽子 | Rank:195 漏洞数:39 | 菜鸟 ,菜渣, 菜呀!)

    关注

  15. 2015-03-02 09:43 | 大亮 ( 普通白帽子 | Rank:306 漏洞数:65 | 慢慢挖洞)

    代码审计大牛都是土豪

  16. 2015-03-02 09:53 | Ricter ( 实习白帽子 | Rank:59 漏洞数:15 | 渣渣一个)

    @phith0n 感觉是 StaticFileHandler 的..

  17. 2015-03-02 12:01 | est ( 路人 | Rank:2 漏洞数:1 | 本id和邪㈧组织无关,虽然也在论坛混过。)

    如果真是StaticFileHandler,而且是windows only,那么估计没人理会这漏洞。。。。。。。。生产环境中这个招的也只能说活该呃。。。。。。

  18. 2015-06-04 09:08 | Sunshie ( 实习白帽子 | Rank:58 漏洞数:10 | http://phpinfo.me)

    django有研究吗

  19. 2015-06-04 10:00 | 大漠長河 ( 实习白帽子 | Rank:43 漏洞数:7 | ̷̸̨̀͒̏̃ͦ̈́̾( 天龙源景区欢迎您...)

    我只好奇,这问题是如何被发现的,代码审计?大牛们有什么发掘漏洞的高招没

  20. 2015-06-04 11:11 | Hckmaple ( 实习白帽子 | Rank:38 漏洞数:14 | ~~~)

    牛逼